PHP: обратный вызов при входе / выходе из методов класса? - PullRequest
1 голос
/ 14 ноября 2008

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

Прямо сейчас мне нужно вызывать Logger :: logEntry () и Logger :: logExit () в каждом методе для достижения этой цели. Я бы не хотел этого делать:

class TestClass {
    public function tester($arg) {
        Logger::logEntry();
        Logger::info('Parameter $arg => ' . $arg);

        // Do some stuff...

        Logger::logExit();
    }
}

Ответы [ 3 ]

11 голосов
/ 14 ноября 2008

использовать класс-оболочку. этот метод имеет следующие преимущества:

  • нет необходимости изменять базовую структуру класса / сигнатуры методов
  • изменить логирование? просто обновите этот класс
  • вызовы объекта обновления против вставки кода в каждый класс, в который вы хотите войти

.

class LogWatch {
    function __construct($class)    {
        $this->obj  =   $class;
    }

    function __call($method, $args) {
        if (in_array($method, get_class_methods($this->obj) ) ) {
            Logger::logEntry();
            Logger::info('Parameter '.implode(', ', $args) );

            call_user_func_array(array($this->obj, $method), $args);

            Logger::logExit();

        } else {
            throw new BadMethodCallException();
        }
    }
}

$test = new LogWatch(new TestClass() );
$test->tester();

// you can use instances of `LogWatch()` just like your watched class
// including passing appropriate params:
$test->tester($param1, $param2);
5 голосов
/ 14 ноября 2008

Если вы хотите вести журнал функций для отладки, вы можете заглянуть в расширение Xdebug. Нет хорошего способа перехватывать вызовы функций во время выполнения, и любой автоматический перехват увеличит время выполнения.

Используя XDebug, вы можете вместо этого включать его по мере необходимости, а также получать множество других вещей

(Таким образом, XDebug используется с PHPUnit для модульного тестирования и анализа покрытия.)

Проблема с __call

__ call может показаться забавным решением проблемы, но есть 3 проблем с этим, а именно

  • Значительные накладные расходы на выполнение. вы делаете __call -> call_user_func_array, который буквально добавит не один, а два вызова функции к каждому выполнению.

  • Обратные трассировки становятся не поддающимися расшифровке: реальная функция, которую вы пытались вызвать, теряется в море __call и call_user_func_array, что делает чрезвычайно трудным обратное отслеживание, особенно если ваши обратные трассировки идут с включенными списками аргументов.

  • Глупые скрытые функции: Вы возвращаетесь к «скрытию» функций в стиле PHP4, добавляя к ним префикс _, чтобы пользователь не вызывал его напрямую или не видел его, потому что, если имя функции названо так, как оно не будет, __call не сработает, так что у вас уже есть целый класс, полный действительно ужасных имен функций, которые разработчики будут в любом случае вызывать напрямую в разных местах. (И если вы хотите избавиться от __call позже, вам придется переименовать все эти функции, чтобы не нарушать код!)

Таким образом, если вы используете php-код для реализации этого, это приведет к невероятно ужасному коду, с которым любой будущий пользователь вашей кодовой базы NOT захочет работать. Вы гораздо лучше получаете что-то (например, Xdebug), которое может быть добавлено прозрачно, когда вам это нужно, и значительно экономит ваш код.

0 голосов
/ 14 ноября 2008

вы можете использовать магическую функцию __call. Он вызывается, когда никакие функции не соответствуют этому имени. Переименуйте ваши методы так, чтобы они начинались с префикса (например, подчеркивание), и при необходимости установите для них значение private / protected.

class TestClass {
    public function __call($function, $args) {
        Logger::logEntry();
        Logger::info('Parameters: ' . implode(", ", $args);

        $localFunc = "_" . $function;
        $return = $this->$localFunc($args);

        Logger::logExit();

        return $return;
    }

    private function _tester() {
        // do stuff...
        return "tester called";
    }
}

 $t = new TestClass();
 echo $t->tester();
 // "tester called"
...