I am currently just messing around with PHP and I noticed something interesting that I personally haven't noticed. Anonymous functions do not seem to work inside objects. Why?
Example:
$loop = function ($do) {
$i = 2;
$do((object) [
"i" => $i,
"domore" => (function () {
echo "hi";
})
]);
};
$loop(function ($data) {
echo $data->i;
echo $data->domore();
});
Throws Error:
2<br />
<b>Fatal error</b>: Uncaught Error: Call to undefined method stdClass::delay() in [...][...]:16
Stack trace:
#0 [...][...](10): {closure}(Object(stdClass))
#1 [...][...](17): {closure}(Object(Closure))
#2 {main}
thrown in <b>[...][...]</b> on line <b>16</b><br />
Likewise the same code with the return data being an array instead of an object:
$loop = function ($do) {
$i = 2;
$do([
"i" => $i,
"domore" => function () {
echo "hi";
}
]);
};
$loop(function ($data) {
echo $data["i"];
echo $data["domore"]();
});
Simply returns, 2hi
, as expected. This seems like strange behavior to me (someone coming from javascript) so I would appreciate some sort of justification. Note that this code serves no real life purpose so good or bad practice has no influence here. Think educational.
Edit: Laravel does exactly what I want giving me the notion that it is not impossible but I simply implemented it incorrectly in PHP:
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);
})->get();
Anonymous functions work fine in objects. You're getting that error because domore
isn't a method and you're calling it as such, it's a property that happens to be a closure. To distinguish you'll need to use parentheses when addressing the property, e.g.:
$loop(function ($data) {
echo $data->i;
echo ($data->domore)();
});
Outputs:
2hi
Why this is necessary is because methods and properties live in different symbol tables, meaning you can have a property and a method of the same name (please don't do this) and you need to know which is being addressed. E.g.:
$foo = new class
{
public $func;
public function __construct()
{
$this->func = function () {
echo "foo";
};
}
public function func()
{
echo "bar";
}
};
($foo->func)();
$foo->func();
Outputs:
foobar