method_exists() или is_callable()

Просматривая код многих PHP приложений, я замечаю, что функция method_exists() часто используется неуместно, и думаю, что стоит написать об этом пару слов.

Вот типичный пример того, о чем пойдет речь:

  1. if (method_exists($object, 'SomeMethod'))
  2. {
  3. $object->SomeMethod($this, TRUE);
  4. }

Цель этого кода очень легко понять (хоть я и не советую делать так): мы проверяем, имеет ли объект “$object” метод “SomeMethod”, и если имеет, вызываем его с нужными аргументами.

Да, но...

Этот код будет, вероятно, работать очень хорошо в своей области видимости, но что если методы объекта не видно (т.е. это частные или защищенные методы)? PHP функция method_exists() ведет себя соответственно названию: проверяет, имеет ли класс или объект метод с таким именем, и возвращает True, если это так, или False, в противоположном случае; видимость метода не учитывается. Итак, если вы проверите при помощи method_exists() существование частного или защищенного метода (не доступные в текущей области видимости), при вызове его вы получите ошибку: “Fatal error: Call to private method…”, которая сразу завершит работу приложения.

Применяйте инструменты по их предназначению

Истинное назначение предыдущего кода, на самом деле – узнать, может ли приложение вызвать метод у объекта.

По этому (среди других причин) is_callable() одна из встроенных в PHP функций.

Как это работает?

Первым параметром в is_callable() передается переменная псевдотипа callback, в нашем случае - массив из двух элементов: объект или строка с названием класса и строка с названием метода. Если в текущей области видимости метод может быть вызван - is_callable() вернет True, если же нет - False.

  1. if (is_callable(array($object, 'SomeMethod')))
  2. {
  3. $object->SomeMethod($this, TRUE);
  4. }

Этот код показывает различия между method_exists() и is_callable():

  1. class Foo {
  2. public function PublicMethod() {}
  3. private function PrivateMethod() {}
  4. public static function PublicStaticMethod() {}
  5. private static function PrivateStaticMethod() {}
  6. }
  7. $foo = new Foo();
  8. $callbacks = array(
  9. array($foo, 'PublicMethod'),
  10. array($foo, 'PrivateMethod'),
  11. array($foo, 'PublicStaticMethod'),
  12. array($foo, 'PrivateStaticMethod'),
  13. array('Foo', 'PublicMethod'),
  14. array('Foo', 'PrivateMethod'),
  15. array('Foo', 'PublicStaticMethod'),
  16. array('Foo', 'PrivateStaticMethod'),
  17. );
  18. foreach ($callbacks as $callback) {
  19. var_dump($callback);
  20. var_dump(method_exists($callback[0], $callback[1])); // 0: объект/имя класса, 1: имя метода
  21. var_dump(is_callable($callback));
  22. echo str_repeat('-', 40), "\n";
  23. }

Запустите этот код, и вы увидите, что каждый тест возвращает True для method_exists(), даже для защищенных методов, в отличие от is_callable().

Дополнительная информация

is_callable() имеет и другие применения, например, проверка синтаксиса без проверки реального существования функции или метода.

Так же как и method_exists(), is_callable() может инициализировать процесс автоматической загрузки класса, если он еще не загружен.

Если же объект имеет "магический метод" __call(), то is_callable() вернет True, в отличае от method_exists(), который вернет False. В php 5.3.0 есть метод __callStatic(), и если описать его для объекта, is_callable() тоже будет работать верно.

Все остальное можно найти в документации PHP.

Rate It! (Average 4.00, 3 votes)

Related Posts

8 Responses to method_exists() или is_callable()

  1. gravatar

    А интерфейс Reflection не лучше ли использовать для классов и их методов?

  2. gravatar

    web-junior, да, возможно, так будет лучше

  3. gravatar

    @web-junior: не всегда нужна вся та мощь, которую предоставляет рефлексия;)

  4. gravatar

    Полностью согласен с web-junior, использование для классов и методов обеспечить более функциональную работу.

  5. gravatar

    @hazzik: ИМХО, мощь рефлексии не нужна только в одном случае - в функциях (и вообще в процедурно-ориентированном подходе к программированию;)). Здесь можно обойтись функциями method_exists() и is_callable().
    А для классов рефлексия как раз то, что нужно.

  6. gravatar

    @web-junior
    Рефлексия нужна только в исключительных случаях. Активное ее использование в приложении (не во фреймворке) говорит о плохом дизайне.

  7. gravatar

    @hazzik
    Может быть объясните, как рефлексия портит дизайн приложения?

  8. gravatar

    Я тоже согласен с web-junior, рефлекцию надо юзать, почему кто-то против внутренностей самого ядра? Я также юзаю эксепшены, dir, итераторы и т.д.

    Даже сам Zend юзает ReflectionClass, чё плохой тон? ФВ Кохана в классе request юзает ReflectionClass, FirePHP - тоже юзает его и тд. У них тоже плохой дзайн????

Leave a Reply

Mail will not be published