在很多產品應用中,我們經常能夠看到以下這種用法,它用來檢查一個對象裡的方法是否存在。
<?php if (method_exists($object, 'SomeMethod')) { $object->SomeMethod($this, TRUE); }?>
這段代碼的目的比較容易理解,有一個對象為$object,我們想知道它是否有一個方法為SomeMethod,如果有,就調用此方法。
這個代碼看起來正確,而且在大部分的時候運行也會正常。但是如果這個$object對象的方法對於當前的運行環境是不可見的,程式還能正常運行嗎?正如這個函數名方法存在一樣,只是對我們提供的類或對象檢查是否有我們所期望的方法,如果有,就返回TRUE,如果沒有,就返回FALSE,這裡並沒有考慮可見度的問題。所以,當你恰好判斷一個私人或者受保護的方法時,你能夠得到一個正確的返回,但是執行的時候,會得到一個“Fatal Error”錯誤警告。
上面這段代碼的真正意圖應該理解為:對於提供的類或者對象,我們能否在當前的範圍中調用它的SomeMethod方法。而這正是is_callable()函數存在的目的。is_callable()函數接收一個回調參數,可以指定一個函數名稱或者一個包含方法名和對象的數組,如果在當前範圍中可以執行,就返回TRUE。
<?php if (is_callable(array($object, 'SomeMethod'))) { $object->SomeMethod($this, TRUE); }?>
下面來舉個例子來說明兩者的區別
<?phpclass Foo { public function PublicMethod(){} private function PrivateMethod(){} public static function PublicStaticMethod(){} private static function PrivateStaticMethod(){}} $foo = new Foo();$callbacks = array( array($foo, 'PublicMethod'), array($foo, 'PrivateMethod'), array($foo, 'PublicStaticMethod'), array($foo, 'PrivateStaticMethod'), array('Foo', 'PublicMethod'), array('Foo', 'PrivateMethod'), array('Foo', 'PublicStaticMethod'), array('Foo', 'PrivateStaticMethod'), ); foreach ($callbacks as $callback){ var_dump($callback); var_dump(method_exists($callback[0], $callback[1])); var_dump(is_callable($callback)); echo str_repeat('-', 10); echo '<br />';}
執行上面的指令碼後,我們會清晰地看到兩個函數間的差別。
is_callable()還有其他的用法,例如,不檢查所提供的類或方法,只檢查函數或方法的文法是否正確。像method_exists()一樣,is_callable()可以觸發類的自動載入。
如果一個對象存在魔術方法__call,在進行方法判斷時method_exists()會返回FALSE,而is_callable()會返回TRUE。
<?phpclass MethodTest { public function __call($name, $arguments){ echo 'Calling object method ' . $name . ' ' .implode(', ', $arguments); echo '<br />'; }}$obj = new MethodTest();$obj->runtest('in object context');var_dump(method_exists($obj,'runtest'));var_dump(is_callable(array($obj,'runtest')));echo '<br />';
運行結果
Calling object method runtest in object context
bool(false) bool(true)
在很多產品應用中,我們經常能夠看到以下這種用法,它用來檢查一個對象裡的方法是否存在。
<?phpif (method_exists($object, 'SomeMethod')) { $object->SomeMethod($this, TRUE); }?>
這段代碼的目的比較容易理解,有一個對象為$object,我們想知道它是否有一個方法為SomeMethod,如果有,就調用此方法。
這個代碼看起來正確,而且在大部分的時候運行也會正常。但是如果這個$object對象的方法對於當前的運行環境是不可見的,程式還能正常運行嗎?正如這個函數名方法存在一樣,只是對我們提供的類或對象檢查是否有我們所期望的方法,如果有,就返回TRUE,如果沒有,就返回FALSE,這裡並沒有考慮可見度的問題。所以,當你恰好判斷一個私人或者受保護的方法時,你能夠得到一個正確的返回,但是執行的時候,會得到一個“Fatal Error”錯誤警告。
上面這段代碼的真正意圖應該理解為:對於提供的類或者對象,我們能否在當前的範圍中調用它的SomeMethod方法。而這正是is_callable()函數存在的目的。is_callable()函數接收一個回調參數,可以指定一個函數名稱或者一個包含方法名和對象的數組,如果在當前範圍中可以執行,就返回TRUE。
<?php if (is_callable(array($object, 'SomeMethod'))) { $object->SomeMethod($this, TRUE); }?>
下面來舉個例子來說明兩者的區別
<?php class Foo { public function PublicMethod(){} private function PrivateMethod(){} public static function PublicStaticMethod(){} private static function PrivateStaticMethod(){}}$foo = new Foo();$callbacks = array( array($foo, 'PublicMethod'), array($foo, 'PrivateMethod'), array($foo, 'PublicStaticMethod'), array($foo, 'PrivateStaticMethod'), array('Foo', 'PublicMethod'), array('Foo', 'PrivateMethod'), array('Foo', 'PublicStaticMethod'), array('Foo', 'PrivateStaticMethod'), ); foreach ($callbacks as $callback){ var_dump($callback); var_dump(method_exists($callback[0], $callback[1])); var_dump(is_callable($callback)); echo str_repeat('-', 10); echo '<br />';}
執行上面的指令碼後,我們會清晰地看到兩個函數間的差別。
is_callable()還有其他的用法,例如,不檢查所提供的類或方法,只檢查函數或方法的文法是否正確。像method_exists()一樣,is_callable()可以觸發類的自動載入。
如果一個對象存在魔術方法__call,在進行方法判斷時method_exists()會返回FALSE,而is_callable()會返回TRUE。
<?phpclass MethodTest { public function __call($name, $arguments){ echo 'Calling object method ' . $name . ' ' .implode(', ', $arguments); echo '<br />'; }}$obj = new MethodTest();$obj->runtest('in object context');var_dump(method_exists($obj,'runtest'));var_dump(is_callable(array($obj,'runtest')));echo '<br />';
運行結果
Calling object method runtest in object context
bool(false) bool(true)