Req #71352 [Opn->Wfx]: instanceof magic method

From: Date: Fri, 29 Jan 2016 18:17:05 +0000
Subject: Req #71352 [Opn->Wfx]: instanceof magic method
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-198963@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71352&edit=1 ID: 71352 Updated by: willfitch@php.net Reported by: tom at r dot je Summary: instanceof magic method -Status: Open +Status: Wont fix Type: Feature/Change Request Package: *General Issues Operating System: * PHP Version: 7.0.2 Block user comment: N Private report: N Previous Comments: ------------------------------------------------------------------------ [2016-01-29 18:16:11] willfitch@php.net This is a feature request - not an issue. For major feature requests, an RFC should be created explicitly defining the feature itself. Note - you'll need a sponsor to author this change in the event you aren't able to provide a patch. Before doing that, I think the first step would be to add the wiki page, then get a feeler from internals on the idea. I sense there will be quite a bit of pushback. ------------------------------------------------------------------------ [2016-01-12 16:48:01] tom at r dot je Description: ------------ Currently there is no way to make a wrapper without using eval() we see this in PHPUnit: https://github.com/sebastianbergmann/phpunit-mock-objects/blob/master/src/Framework/MockObject/Generator.php To generate a mock object PHPUnit has to generate the string ``` class NewClass extends OldClass { public function oldMethod() { } public function oldMethod() { } } ``` and then use eval() to dynamically create this class. This takes a lot of effort and obviously is not a great solution. It would be better, for this and other uses where a wrapper is useful (such as AOP) if this was possible: ``` class Wrapper { private $object; public function __construct($object) { $this->object = $object; } public function __call($func, $args) { $this->object->$func(...$args); } public function __set($name, $value) { $this->object->$name = $value; } public function __get($name) { return $this->object->$name; } } ``` This will act as a wrapper for $object using new Wrapper(new MyObj) however this breaks, and the reason PHPUnit has to use eval is because the wrapper isn't actually an instance of the type being wrapped so this code fails: ``` function processObject(MyObj $obj) { } ``` This works: processObject(new MyObj); but this does not: processObject(new Wrapper(new MyObj)); It would be better if there was a way to make an object pretend to be another type. My suggestion is this: ``` ``` class Wrapper { private $object; public function __construct($object) { $this->object = $object; } public function __call($func, $args) { $this->object->$func(...$args); } public function __set($name, $value) { $this->object->$name = $value; } public function __get($name) { return $this->object->$name; } public function __instanceof($name) { return $name == get_class($this->object; } } ``` The __instanceof method would be called when an object is passed into a method with a type hint and the object is the wrong type. Rather than just erroring, the instanceof method is called with the type-hinted class name as an argument and the class can then pretend to be another class. This may need to be an interface so that __call works. There are several uses for this, an obvious one is PHPUnit's mock objects and another one would be being able to better implement Aspect Oriented Programming, something which needs the same workaround as PHPUnit currently. ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=71352&edit=1

« previous php.bugs (#198963) next »