回調這兩個字,想必接觸過javascript的人都不會陌生.我們的php也擁有回調函數和閉包的概念. 那麼在PHP中如何檢查它是一個可調用的函數呢? 下面開始正式介紹一些方法,來檢測這個問題。
首先介紹一個簡單的一點的:
1. 檢查函數是否存在,如果存在,那麼就調用該函數.同時將參數附加進去.
<?php
function invoke($name){
if(function_exists($name)){
$args = array_slice(func_get_args(),0,1);
call_user_func_array($name,$args);
}
die("no function");
}
function test(){
echo 1;
}
invoke("test"); // 1
invoke("test2"); // no function
這裏我們通過function_exists 來檢測是否爲一個函數.如果 爲函數的話就立即調用函數。如果不爲函數則die。
接下來我們如果把函數切換成一個類方法,那麼我們該如何檢驗呢?
2.1 檢查類的方法是否存在
<?php
class A{
public function foo(){
echo 'foo';
}
protected static function bar(){
echo 'bar';
}
}
function isValidMethod($class,$method){
return method_exists($class,$method) === true ? 'true' : 'false';
}
function invoke($class,$method){
return call_user_func(array($class,$method));
}
print isValidMethod('A','foo');
print isValidMethod('A','bar');
$a = new A();
print isValidMethod($a,'foo');
print isValidMethod($a,'bar');
method_exists 能檢查出對象是否存在指定的方法,該方法不管是 static 還是 final 還是 abstract 還是 默認狀態。也不管是否爲 public , private 還是 protected. 只要是符合語法的類方法都能夠被檢測出,但是無法檢測出使用魔法方法__call的函數
2.2 無法檢測出__call 調用的函數
<?php
class A{
public function exists(){
return true;
}
public function __call($name,$param =array()){
if(strpos($name,"no") !== -1){
$action = lcfirst(substr($name, 2));
if(method_exists($this, $action)){
return !call_user_func_array(array($this,$action),$param);
}
}
return null;
}
}
function isValidMethod($class,$method){
return method_exists($class,$method) === true ? 'true' : 'false';
}
function invoke($class,$method){
return call_user_func(array($class,$method));
}
$a = new A();
print isValidMethod($a,'exists'); // true
print isValidMethod($a,'noExists'); // false
var_dump(invoke($a,'exists')); // true
var_dump(invoke($a,'noExists')); // true
這裏我們可以看出來,method_exists能檢測出用戶定義的方法,但是不能使用call_user_func之類的方法調用那些被protected和private的方法.
接下來我們來看看一個具有豐富功能的檢測函數is_callable. 實際上php有一種對象叫做Callable。凡屬於這種對象的字符串,數組都具備回調的能力。
3. 1 使用 is_callable
<?php
class A{
public function exists(){
return true;
}
private function foo(){
echo 'foo';
}
private static function bar(){
echo 'bar';
}
}
function invoke($class,$method){
return call_user_func(array($class,$method));
}
print is_callable('A::exists'); // true
print is_callable('invoke'); // true
$a = new A();
print is_callable(array($a,'exists')); // true
var_dump(is_callable(array($a,'foo'))); // false
var_dump(is_callable(array($a,'foo'),true)); // true
var_dump(is_callable(array($a,'foo'),false)); //false
從上面可以看出來 is_callable 可以判斷出是否能夠進行調用。默認第二個參數爲false,表示該回調操作有權限能夠被調用,而如果爲true的話,表示只要能檢測出存在具有回調的格式就好。
如果設置了__call 函數的話,那麼檢測出來的任何方法都是返回true的。所以這一點需要大家注意,謹慎使用__get ,或者你可以配合method_exists來縮小 is_callable的範圍。
3.2 is_callable的第三個參數
它允許傳遞一個變量,給該變量賦於一個字符串格式的值。
var_dump(is_callable(array($a,'foo'),false),$name); //false
// 值大概如下
// $name = A::foo()
經過一番的學習之後,我對 is_callable的理解又有了更多的認識。在現在的php環境下,使用call_user_func 之類的函數越來越多。我們要判多出是否可以用來回調。