Php call_user_func binds this arg as a javascript call

In Javascript, I can bind this to another function and call it using .call or .apply

In PHP, I can do this with call_user_func or call_user_func_array , but how can I bind $this to a function?

JavaScript:

 function greet() { alert('Hello ' + this.name); } function SomeClass() {} SomeClass.prototype = { name: 'John', test: function() { greet.call(this); } } var me = new SomeClass(); me.test(); // Hello John 

PHP:

 function greet() { echo 'Hello ' . $this->name; } class SomeClass { public $name = 'John'; function test() { call_user_func('greet'); } } $me = new SomeClass; $me->test(); // Fatal error: Using $this when not in object context 

UPDATE:

Thanks to @deceze for the idea of Reflection , I found these solutions, but I don’t think it is good for performance (x10 is slower than a direct call), but very clear when reading.

I wrote two functions:

 // See also Javascript: Function.prototype.apply() function function_apply($fn, $thisArg, $argsArray = array()) { static $registry; if (is_string($fn)) { if (!isset($registry[$fn])) { $ref = new \ReflectionFunction($fn); $registry[$fn] = $ref->getClosure(); } $fn = $registry[$fn]; } return call_user_func_array($fn->bindTo($thisArg), $argsArray); } // See also Javascript: Function.prototype.call() function function_call($fn, $thisArg /*, arg1, arg2 ... */) { return function_apply($fn, $thisArg, array_slice(func_get_args(), 2)); } 

and replace call_user_func with function_call :

 function greet() { echo 'Hello ' . $this->name; } class SomeClass { public $name = 'John'; function test() { function_call('greet', $this); } } $me = new SomeClass; $me->test(); // Hello John 
+5
source share
2 answers

PHP is not JavaScript: you cannot freely mix functions defined inside and outside classes by switching their context as you call them. Any attempt to use $this way you described will result in a fatal error: Using $this when not in object context .

Again, the same effect can be achieved with a simple convention for classless functions: pass in the context with which they should work as your first parameter. Apparently, you can only use the open interface of the context object, but again, it is similar to JavaScript. In addition, as a bonus, you can check the type with a class hint. For instance:

 function greet(SomeClass $_this) { echo 'Hello ' . $_this->name; } class SomeClass { public $name = 'John'; function test() { call_user_func('greet', $this); } } $me = new SomeClass; $me->test(); // Hello John 
+3
source

you can use the function Closure :: bind

 <?php class AAA { public function ccc() { $bbb = new BBB; $r = $bbb->abc()[0]; var_dump($r, Closure::bind($r, $this)); } } class BBB { public function abc() { return [function () { }]; } } $aaa = new AAA; $aaa->ccc(); 

and result

 object(Closure)#3 (1) { ["this"]=> object(BBB)#2 (0) { } } object(Closure)#4 (1) { ["this"]=> object(AAA)#1 (0) { } } 
+1
source

Source: https://habr.com/ru/post/1209644/


All Articles