From [1]:
Objective-C permits a class to wholly replace another class within a
program. The replacing class is said to "pose as" the target class.
All messages sent to the target class are then instead received by
the posing class.
There are several restrictions on which classes can pose:
* A class may only pose as one of its direct or indirect
superclasses.
[The other restrictions do not apply to PHP]
Earlier this year, Johannes implemented class posing for PHP as follows:
<?php
class Foo {}
class Bar extends Foo {}
function new_overload($className)
{
if ($className == 'Foo') {
return new Bar;
}
// ...
}
$o = new Foo;
// $o is an object of Foo.
register_new_overload('new_overload');
$o = new Foo;
// $o is an object of Bar.
?>
We (Johannes, Marcus, Sara, and myself) then discussed where to put this
functionality. Outside of core, there were two places that both make
sense: pecl/operator and pecl/runkit.
However, to make this a viable mechanism that can be used in tools such
as PHPUnit (for which I could really use this functionality), we agreed
that it actually belongs into the core.
Opinions? Needless to say that I would love to see this in PHP 5.3 ;-)
--
[1] http://en.wikipedia.org/wiki/Objective_C#Posing
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
would it be possible to overload final classes?
- David
Am 02.10.2007 um 11:32 schrieb Sebastian Bergmann:
From [1]:
Objective-C permits a class to wholly replace another class
within a
program. The replacing class is said to "pose as" the target class.
All messages sent to the target class are then instead received by
the posing class.There are several restrictions on which classes can pose:
* A class may only pose as one of its direct or indirect superclasses. [The other restrictions do not apply to PHP]
Earlier this year, Johannes implemented class posing for PHP as
follows:<?php
class Foo {}
class Bar extends Foo {}function new_overload($className)
{
if ($className == 'Foo') {
return new Bar;
}// ...
}
$o = new Foo;
// $o is an object of Foo.register_new_overload('new_overload');
$o = new Foo;
// $o is an object of Bar.
?>We (Johannes, Marcus, Sara, and myself) then discussed where to
put this
functionality. Outside of core, there were two places that both make
sense: pecl/operator and pecl/runkit.However, to make this a viable mechanism that can be used in tools
such
as PHPUnit (for which I could really use this functionality), we
agreed
that it actually belongs into the core.Opinions? Needless to say that I would love to see this in PHP
5.3 ;-)--
[1] http://en.wikipedia.org/wiki/Objective_C#Posing--
Sebastian Bergmann http://sebastian-
bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514
B85B 5D69
would it be possible to overload final classes?
- David
Am 02.10.2007 um 11:32 schrieb Sebastian Bergmann:
From [1]:
Objective-C permits a class to wholly replace another class
within a
program. The replacing class is said to "pose as" the target class.
All messages sent to the target class are then instead received by
the posing class.There are several restrictions on which classes can pose:
* A class may only pose as one of its direct or indirect superclasses. [The other restrictions do not apply to PHP]
Earlier this year, Johannes implemented class posing for PHP as
follows:<?php
class Foo {}
class Bar extends Foo {}function new_overload($className)
{
if ($className == 'Foo') {
return new Bar;
}// ...
}
$o = new Foo;
// $o is an object of Foo.register_new_overload('new_overload');
$o = new Foo;
// $o is an object of Bar.
?>We (Johannes, Marcus, Sara, and myself) then discussed where to
put this
functionality. Outside of core, there were two places that both make
sense: pecl/operator and pecl/runkit.However, to make this a viable mechanism that can be used in tools
such
as PHPUnit (for which I could really use this functionality), we
agreed
that it actually belongs into the core.Opinions? Needless to say that I would love to see this in PHP
5.3 ;-)
You're code looks like a factory. Is that your intention? Maybe
__factory would be a more obvious name?
--
Richard Quadling
Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
"Standing on the shoulders of some very clever giants!"
Richard Quadling schrieb:
You're code looks like a factory. Is that your intention? Maybe
__factory would be a more obvious name?
The application of this mechanism is not limited to implementing
factories and singletons.
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
Hi Sebastian and PHP list,
That's a very interesting idea and I'd use it too. Yesterday night I
was developing a set of classes that it could apply this idea too.
Altho I found this idea really interesting, I have a suggestion for
it. Instead of use a function to handle new overloads, I suggest a
magic method, something like __new.
The idea behind this:
<?php
class Foo {
function __construct($type = 'Foo') { echo 'Created ', $type; }
function __new( $type ) {
if ($type == 'Bar') {
return new Bar();
}
}
}
class Bar {
function __construct() { echo 'Bar here!'; }
}
$bar = new Foo('Bar'); // Creates Bar instance
?>
Dunno the impact of this in the source, but my humble idea is that it
independs of inheritance. Of course this would be more acceptable for
super and extended classes, and here is a true usage of it:
class Validator {
private $_country;
function __construct() {}
function __new($country) {
switch ($country) {
case 'Brazil': return new Validator_Brazil();
default: return new Validator_US();
}
}
}
interface IValidator_Country {
function validate($type, $value);
}
class Validator_Brazil implements IValidator_Country {
function __construct() { ... }
function validate($type, $value) { ... }
}
class Validator_US implements IValidator_Country {
function __construct() { ... }
function validate($type, $value) { ... }
}
$o = new Validator('Brazil'); // Creates Validator_Brazil
echo ($o->validate('zip', '13561000')) ? 'Zip code is valid' : 'Zip is
not valid';
The basic idea is to check for __new existance and call it instead of
__construct. If there's no return or null after __new call, then call
the __contruct as currently it does.
So, what do you think??? =)
Regards,
From [1]:
Objective-C permits a class to wholly replace another class within a
program. The replacing class is said to "pose as" the target class.
All messages sent to the target class are then instead received by
the posing class.There are several restrictions on which classes can pose:
* A class may only pose as one of its direct or indirect superclasses. [The other restrictions do not apply to PHP]
Earlier this year, Johannes implemented class posing for PHP as follows:
<?php
class Foo {}
class Bar extends Foo {}function new_overload($className)
{
if ($className == 'Foo') {
return new Bar;
}// ...
}
$o = new Foo;
// $o is an object of Foo.register_new_overload('new_overload');
$o = new Foo;
// $o is an object of Bar.
?>We (Johannes, Marcus, Sara, and myself) then discussed where to put this
functionality. Outside of core, there were two places that both make
sense: pecl/operator and pecl/runkit.However, to make this a viable mechanism that can be used in tools such
as PHPUnit (for which I could really use this functionality), we agreed
that it actually belongs into the core.Opinions? Needless to say that I would love to see this in PHP 5.3 ;-)
--
[1] http://en.wikipedia.org/wiki/Objective_C#Posing--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69--
--
Guilherme Blanco - Web Developer
CBC - Certified Bindows Consultant
Cell Phone: +55 (16) 9166-6902
MSN: guilhermeblanco@hotmail.com
URL: http://blog.bisna.com
São Carlos - SP/Brazil
Guilherme Blanco schrieb:
Altho I found this idea really interesting, I have a suggestion for
it. Instead of use a function to handle new overloads, I suggest a
magic method, something like __new.
__new() was what I initially proposed to Johannes but IIRC there were
some performance implications with that. Johannes?
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
Hi,
Guilherme Blanco schrieb:
Altho I found this idea really interesting, I have a suggestion for
it. Instead of use a function to handle new overloads, I suggest a
magic method, something like __new.__new() was what I initially proposed to Johannes but IIRC there were
some performance implications with that. Johannes?
The initial implementation Sebastian refers to is a conference hack I
did, which was done to see whether it's possible and give Sebastian a
thing to test the feature - there wasn't much thinking involved :-)
For an extension, which the current implementation is, using the
register function is the best approach I see. Else we would have to to
the look-up for the __new() function on every object instantiation. The
existence of that function can't be cached since it could be defined any
time. (While for an extension, used for testing, performance is not #1
prio)
If such an feature would become an engine feature one could cache the
declaration of __new() during the function declaration - which in that
case would, indeed, be the best.
But all that are implementation details. The question is: Do we need
such a feature inside Core PHP or is an extension overloading ZEND_NEW
enough?
The only need I see is mocking objects for a unit test. This is usually
done on a test system so installing such an extension shouldn't be to
hard (especially for somebody who is able to do unit tests using mock
objects...)
One might also think about taking XDebug's code coverage stuff and the
ZEND_NEW overloading and other stuff to build a phpunit extension - but
that's no topic for internals :-)
johannes
For an extension, which the current implementation is, using the
register function is the best approach I see. Else we would have to to
I would prefer some special function to new handler. This feature has
very narrow use (I still not entirely convinced it even belongs to core
- it's too kludgy and can be easily worked around by using correct
patterns).
But all that are implementation details. The question is: Do we need
such a feature inside Core PHP or is an extension overloading ZEND_NEW
enough?
I'd say it's better to overload class' create_object and not an opcode.
And I personally don't feel it's something that should be widely used,
so Core may not be the best place. Maybe having some test extension
(disabled by default, enabled on test machines) would be a better way?
--
Stanislav Malyshev, Zend Software Architect
stas@zend.com http://www.zend.com/
(408)253-8829 MSN: stas@zend.com
Ideally think I'd prefer it finer grained...
interface A
{
}
class AImpl implements A
{
}
register('A', function() { return new AImpl(); });
register('Foo', function() { return new Bar(); });
$foo = new Foo();
$a = new A();
Would also require functions being values... Which would also be nice.
J
-----Original Message-----
From: news [mailto:news@sea.gmane.org] On Behalf Of Sebastian Bergmann
Sent: 02 October 2007 10:33
To: internals@lists.php.net
Subject: [PHP-DEV] Class PosingFrom [1]:
Objective-C permits a class to wholly replace another
class within a
program. The replacing class is said to "pose as" the target class.
All messages sent to the target class are then instead received by
the posing class.There are several restrictions on which classes can pose:
* A class may only pose as one of its direct or indirect superclasses. [The other restrictions do not apply to PHP]
Earlier this year, Johannes implemented class posing for PHP
as follows:<?php
class Foo {}
class Bar extends Foo {}function new_overload($className)
{
if ($className == 'Foo') {
return new Bar;
}// ...
}
$o = new Foo;
// $o is an object of Foo.register_new_overload('new_overload');
$o = new Foo;
// $o is an object of Bar.
?>We (Johannes, Marcus, Sara, and myself) then discussed where
to put this functionality. Outside of core, there were two
places that both make
sense: pecl/operator and pecl/runkit.However, to make this a viable mechanism that can be used in
tools such as PHPUnit (for which I could really use this
functionality), we agreed that it actually belongs into the core.Opinions? Needless to say that I would love to see this in
PHP 5.3 ;-)--
[1] http://en.wikipedia.org/wiki/Objective_C#Posing--
Sebastian Bergmann
http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867
C514 B85B 5D69--
To
unsubscribe, visit: http://www.php.net/unsub.php
Earlier this year, Johannes implemented class posing for PHP as follows:
<?php
class Foo {}
class Bar extends Foo {}function new_overload($className)
{
if ($className == 'Foo') {
return new Bar;
}// ...
}
$o = new Foo;
// $o is an object of Foo.register_new_overload('new_overload');
$o = new Foo;
// $o is an object of Bar.
?>
This looks like factory pattern. What's wrong with implementing it as
factory?
However, to make this a viable mechanism that can be used in tools such
as PHPUnit (for which I could really use this functionality), we agreed
that it actually belongs into the core.
I personally don't see much of the use of it in the core, and it
definitely adds very "magic" things - you don't know anymore what class
you are instantiating when you run "new Foo". My opinion is it belongs
to places like "runkit" which do tricks with the language, but I don't
see much use for it in the core. Could you explain more why existing
pattern won't work for the same?
Stanislav Malyshev, Zend Software Architect
stas@zend.com http://www.zend.com/
(408)253-8829 MSN: stas@zend.com
Stanislav Malyshev schrieb:
This looks like factory pattern. What's wrong with implementing it as
factory?
Like I said before, the factory and singleton patterns are just example
applications of this mechanism.
What I want to use them for in PHPUnit is improving the Mock Objects
system.
Let us consider the following code:
public function foo()
{
$bar = new Bar;
$returh = $bar->doSomething();
// do something with $return
return 'some value';
}
When I want to test the foo() method, I want to stub out the usage of
the Bar class, for example, and have Bar::doSomething() return a
pre-configured value instead of performing its normal operation.
As I cannot pass a stubbed version of $bar into the method, I currently
do not have a way to stub Bar.
With class posing, however, I can override the "new Bar" and have it
create an object of my stub implementation of Bar instead.
I hope this makes my motivation for the feature more clear.
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
Like I said before, the factory and singleton patterns are just example
applications of this mechanism.
Right, but I'd like to see why we need it - i.e. what it allows to do
that other things don't. I'm afraid that we might have a case of
featuritis here (not meaning this specific proposal, I'm talking more in
general state of affairs) in 5.3 - we will turn PHP from simple language
into minefield of magic methods where you can't possibly know what the
code you are looking at actually does. It might be useful for some
applications but might hurt the language as a whole. It also can have a
lot of implications what have unintended - i.e. how typehints are
supposed to work with this? How reflection and autoloading would work?
What with static methods and variables?
What I want to use them for in PHPUnit is improving the Mock Objects
system.
As far as I know, Java has unit tests but doesn't allow replacing
classes. How does it work in Java?
I hope this makes my motivation for the feature more clear.
Yes, I can see the motivation now, but I'm not entirely convinced
allowing to replace classes with other classes would be the best
solution. I know there are OO languages extensively using unit testing
and not having this feature - I'd propose looking into how it is done there.
Stanislav Malyshev, Zend Software Architect
stas@zend.com http://www.zend.com/
(408)253-8829 MSN: stas@zend.com
Stanislav Malyshev schrieb:
As far as I know, Java has unit tests but doesn't allow replacing
classes. How does it work in Java?
Stubs / Mock Objects !== Unit Tests. Class Posing allows for better
stubs / mock objects which in turn are tools to write better unit
tests.
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
Stubs / Mock Objects !== Unit Tests. Class Posing allows for better
stubs / mock objects which in turn are tools to write better unit
tests.
OK, I see that. The question is - does any of the known unit test
systems use mock objects? Does it do that in the language that doesn't
allow "new Foo" to create object of entirely unrelated class? If so -
how it is usually done?
Stanislav Malyshev, Zend Software Architect
stas@zend.com http://www.zend.com/
(408)253-8829 MSN: stas@zend.com
Stanislav Malyshev schrieb:
lot of implications what have unintended - i.e. how typehints are
supposed to work with this? How reflection and autoloading would work?
Typehints continue working because of the restriction that applies to
this mechanism (see other mail(s)).
Reflection{Class|Object}($object) does not care how $object has been
created.
__autoload() will be trigger just as before by the new operators inside
the new-handler function (where they are, of course, not overloaded).
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
Hi,
public function foo()
{
$bar = new Bar;
[...]
}When I want to test the foo() method, I want to stub out the usage of
the Bar class, for example, and have Bar::doSomething() return a
pre-configured value instead of performing its normal operation.
This is where you'd start refactoring the above sourcecode. I don't like
this idea at all, because it really only helps you with testing legacy
source you might not be able to or do not want to change (want to say: rare
use-case IMO).
If you really need to intercept construction, you can still weave your
interception functionality into sourcecode as you'd be doing in any AOP
library. Simply write a stream wrapper for the file:// stream or add a
filter to it to intercept all includes and / or requires your legacy code
might contain and rewrite the sourcecode while loading, replacing "new Foo"
by "newinstance('Foo')" - this might even be possible in a safe manner by
using preg_replace.
- Timm