php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #71352 instanceof magic method
Submitted: 2016-01-12 16:48 UTC Modified: 2016-01-29 18:17 UTC
Votes:4
Avg. Score:3.8 ± 0.8
Reproduced:4 of 4 (100.0%)
Same Version:1 (25.0%)
Same OS:3 (75.0%)
From: tom at r dot je Assigned:
Status: Wont fix Package: *General Issues
PHP Version: 7.0.2 OS: *
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: tom at r dot je
New email:
PHP Version: OS:

 

 [2016-01-12 16:48 UTC] 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.



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-01-29 18:16 UTC] 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-29 18:17 UTC] willfitch@php.net
-Status: Open +Status: Wont fix
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 23 09:01:27 2024 UTC