手册目录: 语言参考---类型---Callback回调类型
参考详情: https://secure.php.net/manual/zh/language.types.callable.php
评论部分:
1. by edanschwartz@gmail.com
你可以使用'self::methodName'作为一个回调函数,但是这样做是很危险的,参见一下例子:
<?php
class Foo {
public static function doAwesomeThings() {
FunctionCaller::callIt('self::someAwesomeMethod');
}
public static function someAwesomeMethod() {
// fantastic code goes here.
}
}
class FunctionCaller {
public static function callIt(callable $func) {
call_user_func($func);
}
}
Foo::doAwesomeThings();
?>
运行出错:
class 'FunctionCaller' does not have a method 'someAwesomeMethod'.因为FunctionCaller并不知道self对应着Foo
基于此,你应该始终使用全类名进行调用,如下:
<?php
FunctionCaller::callIt('Foo::someAwesomeMethod');
?>
2. by computrius@gmail.com
当你指明类的方法以数组的形式回调时(例如.array($this,'myFunc')),回调的方法可以是私有的,但此种情况只适用于类内调用,如果类外调用私有方法将会报错.
<?php
class mc {
public function go(array $arr) {
array_walk($arr, array($this, "walkIt"));
}
private function walkIt($val) {
echo $val . "<br />";
}
public function export() {
return array($this, 'walkIt');
}
}
$data = array(1,2,3,4);
$m = new mc;
$m->go($data); // valid
array_walk($data, $m->export()); // 将会产生警告
?>
输出:
1<br />2<br />3<br />4<br />
warning:
array_walk() expects parameter 2 to be a valid callback, cannot access private method mc::walkIt() in /in/tfh7f on line 22.
3. by Riikka K
他认为使用callable和可变函数进行回调,可能会产生错误,如下代码:
<?php
class foo {
static function callIt(callable $callback) {
$callback();
}
static function doStuff() {
echo "Hello World!";
}
}
foo::callIt('foo::doStuff');
?>
会产生一个error:
Fatal error: Call to undefined function foo::doStuff() in /tmp/code.php on line 4
但是经过我个人在php7上测试,完美通过,所以可能是
Riikka K使用的php版本较低的缘故,这里说明一下.
4. by andrewbessa@gmail.com
你可以使用$this来指定一个回调函数,例如:
<?php
class MyClass {
public $property = 'Hello World!';
public function MyMethod()
{
call_user_func(array($this, 'myCallbackMethod'));
}
public function MyCallbackMethod()
{
echo $this->property;
}
}
?>
5. by metemarkers@gmail.com
你可以像回调一个方法那样回调一个实现了__invoke()魔术方法的对象,__invoke()方法会在你尝试以调用函数的形式调用对象时被自动调用
metemarkers没有给出具体的实例,这里添加一个我自己的例子:
<?php
class CallableClass
{
function __invoke($x) {
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5); //以函数的形式进行调用,会调用__invoke(),输出int(5)
var_dump(is_callable($obj)); //是callable类型的
?>
输出: int(5) bool(true)
这哥们写了一个方法来判定传入的方法是否是callable类型,并可以同时作用多种回调方式,如下是源码:
<?php
/**
* The callable types and normalizations are given in the table below:
*
* Callable | Normalization | Type
* ---------------------------------+---------------------------------+--------------
* function (...) use (...) {...} | function (...) use (...) {...} | 'closure'
* $object | $object | 'invocable'
* "function" | "function" | 'function'
* "class::method" | ["class", "method"] | 'static'
* ["class", "parent::method"] | ["parent of class", "method"] | 'static'
* ["class", "self::method"] | ["class", "method"] | 'static'
* ["class", "method"] | ["class", "method"] | 'static'
* [$object, "parent::method"] | [$object, "parent::method"] | 'object'
* [$object, "self::method"] | [$object, "method"] | 'object'
* [$object, "method"] | [$object, "method"] | 'object'
* ---------------------------------+---------------------------------+--------------
* other callable | idem | 'unknown'
* ---------------------------------+---------------------------------+--------------
* not a callable | null | false
*
* If the "strict" parameter is set to true, additional checks are
* performed, in particular:
* - when a callable string of the form "class::method" or a callable array
* of the form ["class", "method"] is given, the method must be a static one,
* - when a callable array of the form [$object, "method"] is given, the
* method must be a non-static one.
*
*/
function callableType($callable, $strict = true, callable& $norm = null) {
if (!is_callable($callable)) {
switch (true) {
case is_object($callable):
$norm = $callable;
return 'Closure' === get_class($callable) ? 'closure' : 'invocable';
case is_string($callable):
$m = null;
if (preg_match('~^(?<class>[a-z_][a-z0-9_]*)::(?<method>[a-z_][a-z0-9_]*)$~i', $callable, $m)) {
list($left, $right) = [$m['class'], $m['method']];
if (!$strict || (new \ReflectionMethod($left, $right))->isStatic()) {
$norm = [$left, $right];
return 'static';
}
} else {
$norm = $callable;
return 'function';
}
break;
case is_array($callable):
$m = null;
if (preg_match('~^(:?(?<reference>self|parent)::)?(?<method>[a-z_][a-z0-9_]*)$~i', $callable[1], $m)) {
if (is_string($callable[0])) {
if ('parent' === strtolower($m['reference'])) {
list($left, $right) = [get_parent_class($callable[0]), $m['method']];
} else {
list($left, $right) = [$callable[0], $m['method']];
}
if (!$strict || (new \ReflectionMethod($left, $right))->isStatic()) {
$norm = [$left, $right];
return 'static';
}
} else {
if ('self' === strtolower($m['reference'])) {
list($left, $right) = [$callable[0], $m['method']];
} else {
list($left, $right) = $callable;
}
if (!$strict || !(new \ReflectionMethod($left, $right))->isStatic()) {
$norm = [$left, $right];
return 'object';
}
}
}
break;
}
$norm = $callable;
return 'unknown';
}
$norm = null;
return false;
}
?>
本人眼拙,如有任何错误,可以及时与我联系并及时修正.