'What's the shortest way to bind variable $this to a callable object field?
I bound the $this variable with Closure::bind() method (lines 12-13) to my getName() and getAge() methods (lines 4 and 7) so that they can refer to their own member fields (lines 2-3) in an instance of stdClass. It works, but I find this a bit tedious.
Is there any special variable or built-in function that I can refer to the current instance of stdClass inside my getName() and getAge() methods (lines 4 and 7) without calling Closure::bind() method? Or, is there any workaround to this, if any?
PHP Code
$human = (object) [
'name' => 'John Doe',
'age' => 25,
'getName' => function() {
var_dump($this->name);
},
'getAge' => function() {
var_dump($this->age);
},
];
$human->getName = Closure::bind($human->getName, $human);
$human->getAge = Closure::bind($human->getAge, $human);
print_r($human);
($human->getName)();
($human->getAge)();
Sample Output:
stdClass Object
(
[name] => John Doe
[age] => 25
[getName] => Closure Object
(
[this] => stdClass Object
*RECURSION*
)
[getAge] => Closure Object
(
[this] => stdClass Object
*RECURSION*
)
)
string(8) "John Doe"
int(25)
Solution 1:[1]
First of all: despite the question body calling them such, getName and getAge are not methods. In PHP, methods and fields live in separate namespaces: methods are always looked up on the class, whereas fields are looked up on the instance. If the call expressions looked like $human->getName() and $human->getAge() instead of ($human->getName)() and ($human->getAge)(), they would be looking up the corresponding stdClass methods, which of course don’t exist, so they would fail.
Furthermore, once a field value is read, the object where it was read from is discarded and not used any further; it makes no difference that the value obtained happens to be callable. Because the object is discarded, there is nothing to bind the $this variable to inside the closure. This is unlike JavaScript, where methods are exactly equivalent to fields, they share a single namespace, and invoking a function just looked up on an object binds that object as this within the invoked function’s body.
I think what you actually want to accomplish is best achieved with an anonymous class:
$human = new class {
public $name = 'John Doe';
public $age = 25;
public function getName() {
var_dump($this->name);
}
public function getAge() {
var_dump($this->age);
}
};
$human->getName();
$human->getAge();
This makes getName and getAge actually methods, which receive the appropriate $this binding.
You can even make your anonymous class a subclass of stdClass if you insist, though I see no particular reason why.
Solution 2:[2]
I think you should make a better case for why you would want to do this. That said, the Closure::bind() is indeed a bit tedious. There is something you can do, but I doubt you will like it. It goes like this:
$human = (object) [
'name' => 'John Doe',
'age' => 25,
'getName' => function($object) {
var_dump($object->name);
},
'getAge' => function($object) {
var_dump($object->age);
},
];
($human->getName)($human);
($human->getAge)($human);
See: PHP fiddle
Here you admit that, at the time of creation, the functions aren't aware that they are part of an object, when $this would make sense. Therefore you supply the needed object later as an argument, and everything is fine.
Again, creating a normal class would be preferable, if only because it is easier to understand. Remember, you write code to do something, but also because it is a way to communicate your intent to yourself and others.
I thought of another way to do this. Also not what you want, but it kind of works:
$human = (object) [
'name' => 'John Doe',
'age' => 25,
'getName' => function() {
global $human;
var_dump($human->name);
},
'getAge' => function() {
global $human;
var_dump($human->age);
},
];
($human->getName)();
($human->getAge)();
See: PHP fiddle
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | user3840170 |
| Solution 2 |
