【PHP】function_exists , method_exists 與 is_callable的區別

回調這兩個字,想必接觸過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 之類的函數越來越多。我們要判多出是否可以用來回調。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章