객체 속성에 직접 할당 된 클로저 호출
클로저를 변수에 다시 할당 한 다음 호출하지 않고 객체의 속성에 직접 할당 한 클로저를 호출 할 수 있기를 원합니다. 이게 가능해?
아래 코드는 작동하지 않으며 Fatal error: Call to undefined method stdClass::callback()
.
$obj = new stdClass();
$obj->callback = function() {
print "HelloWorld!";
};
$obj->callback();
PHP7부터 할 수 있습니다.
$obj = new StdClass;
$obj->fn = function($arg) { return "Hello $arg"; };
echo ($obj->fn)('World');
또는 Closure :: call () 을 사용하지만 StdClass
.
PHP7 이전 __call
에는 호출을 가로 채서 콜백을 호출 하는 매직 메서드 를 구현해야했습니다 ( StdClass
물론 __call
메서드를 추가 할 수 없기 때문에 불가능합니다 ).
class Foo
{
public function __call($method, $args)
{
if(is_callable(array($this, $method))) {
return call_user_func_array($this->$method, $args);
}
// else throw exception
}
}
$foo = new Foo;
$foo->cb = function($who) { return "Hello $who"; };
echo $foo->cb('World');
당신은 할 수 없습니다
return call_user_func_array(array($this, $method), $args);
에서 __call
몸이 트리거 때문에 __call
무한 루프.
클로저에서 __invoke를 호출하여이를 수행 할 수 있습니다. 이는 객체가 함수처럼 동작하는 데 사용하는 마법 메서드이기 때문입니다.
$obj = new stdClass();
$obj->callback = function() {
print "HelloWorld!";
};
$obj->callback->__invoke();
물론 콜백이 배열 또는 문자열 (PHP에서도 유효한 콜백 일 수 있음) 인 경우에는 작동하지 않습니다. 클로저 및 __invoke 동작이있는 기타 객체에만 해당됩니다.
현재 PHP 7 다음을 수행 할 수 있습니다 :
($obj->callback)();
을 사용하여 가능한 것 같습니다 call_user_func()
.
call_user_func($obj->callback);
우아하지는 않지만 .... @Gordon이 말하는 것은 아마도 유일한 길일 것입니다.
글쎄, 당신이 정말로 주장 한다면 . 또 다른 해결 방법은 다음과 같습니다.
$obj = new ArrayObject(array(),2);
$obj->callback = function() {
print "HelloWorld!";
};
$obj['callback']();
그러나 그것은 가장 좋은 구문이 아닙니다.
그러나, PHP 파서는 항상 취급 T_OBJECT_OPERATOR
, IDENTIFIER
, (
메서드 호출한다. ->
메서드 테이블 을 우회하고 대신 속성에 액세스 할 수있는 해결 방법이없는 것 같습니다 .
I know this is old, but I think Traits nicely handle this problem if you are using PHP 5.4+
First, create a trait that makes properties callable:
trait CallableProperty {
public function __call($method, $args) {
if (property_exists($this, $method) && is_callable($this->$method)) {
return call_user_func_array($this->$method, $args);
}
}
}
Then, you can use that trait in your classes:
class CallableStdClass extends stdClass {
use CallableProperty;
}
Now, you can define properties via anonymous functions and call them directly:
$foo = new CallableStdClass();
$foo->add = function ($a, $b) { return $a + $b; };
$foo->add(2, 2); // 4
Since PHP 7 a closure can be called using the call()
method:
$obj->callback->call($obj);
Since PHP 7 is possible to execute operations on arbitrary (...)
expressions too (as explained by Korikulum):
($obj->callback)();
Other common PHP 5 approaches are:
using the magic method
__invoke()
(as explained by Brilliand)$obj->callback->__invoke();
using the
call_user_func()
functioncall_user_func($obj->callback);
using an intermediate variable in an expression
($_ = $obj->callback) && $_();
Each way has its own pros and cons, but the most radical and definitive solution still remains the one presented by Gordon.
class stdKlass
{
public function __call($method, $arguments)
{
// is_callable([$this, $method])
// returns always true when __call() is defined.
// is_callable($this->$method)
// triggers a "PHP Notice: Undefined property" in case of missing property.
if (isset($this->$method) && is_callable($this->$method)) {
return call_user_func($this->$method, ...$arguments);
}
// throw exception
}
}
$obj = new stdKlass();
$obj->callback = function() { print "HelloWorld!"; };
$obj->callback();
well, it should be emphisized that storing the closure in a variable, and call the varible is actually (wierdly) faster, depending on the call amount, it becomes quite a lot, with xdebug (so very precise measuring), we are talking about 1,5 (the factor, by using a varible, instead of directly calling the __invoke. so instead , just store the closure in a varible and call it.
Here is another way to successfully call object properties as closure.
When you don't want to change core object use this :
$obj = new AnyObject(); // with or without __invoke() method
$obj->callback = function() {
return function () {
print "HelloWorld!";
};
};
$obj->callback();
UPDATE:
$obj = new AnyObject(); // with or without __invoke() method
$obj->callback = function() {
print "HelloWorld!";
};
$callback = $obj->callback;
$callback();
Here's another alternative based on the accepted answer but extending stdClass directly:
class stdClassExt extends stdClass {
public function __call($method, $args)
{
if (isset($this->$method)) {
$func = $this->$method;
return call_user_func_array($func, $args);
}
}
}
Usage example:
$foo = new stdClassExt;
$foo->blub = 42;
$foo->whooho = function () { return 1; };
echo $foo->whooho();
You are probably better off using call_user_func
or __invoke
though.
If you're using PHP 5.4 or above you could bind a callable to the scope of your object to invoke custom behavior. So for example if you were to have the following set up..
function run_method($object, Closure $method)
{
$prop = uniqid();
$object->$prop = \Closure::bind($method, $object, $object);
$object->$prop->__invoke();
unset($object->$prop);
}
And you were operating on a class like so..
class Foo
{
private $value;
public function getValue()
{
return $this->value;
}
}
You could run your own logic as if you were operating from within the scope of your object
$foo = new Foo();
run_method($foo, function(){
$this->value = 'something else';
});
echo $foo->getValue(); // prints "something else"
참고URL : https://stackoverflow.com/questions/4535330/calling-closure-assigned-to-object-property-directly
'developer tip' 카테고리의 다른 글
MySQL-IN () 내의 ORDER BY 값 (0) | 2020.08.20 |
---|---|
위치 0에 C # 데이터 테이블 삽입 열 (0) | 2020.08.20 |
Python의 "is"연산자 이해 (0) | 2020.08.20 |
Linux 쉘 스크립트에 새 줄을 삽입하는 방법은 무엇입니까? (0) | 2020.08.20 |
Heroku NodeJS http에서 https SSL로 강제 리디렉션 (0) | 2020.08.20 |