Перехват метода в PHP 5. * - PullRequest
       13

Перехват метода в PHP 5. *

2 голосов
/ 22 апреля 2010

Я внедряю систему Log для PHP, и я немного застрял.

Вся конфигурация определена в файле XML, в котором объявляется каждый регистрируемый метод. XML хорошо анализируется и преобразуется в многомерный массив (classname => array of methods). Пока все хорошо.

Давайте рассмотрим простой пример:

#A.php
class A {
    public function foo($bar) {
        echo ' // Hello there !';
    }

public function bar($foo) {
    echo " $ù$ùmezf$z !";
}
}

#B.php
class B {
public function far($boo) {
    echo $boo;  
}
}

Теперь допустим, у меня есть этот файл конфигурации:

<interceptor>
<methods class="__CLASS_DIR__A.php">
        <method name="foo">
    <log-level>INFO</log-level>
    <log-message>Transaction init</log-message>
        </method>
</methods>  
<methods class="__CLASS_DIR__B.php">
        <method name="far">
    <log-level>DEBUG</log-level>
    <log-message>Useless</log-message>
        </method>
</methods>
</interceptor>

Я бы хотел ТОЛЬКО В РАБОТЕ (после того как XML-парсер выполнил свою работу):

#Logger.php (its definitely NOT a final version) -- generated by the XML parser
class Logger {
public function __call($name,$args) {
    $log_level = args[0];
    $args = array_slice($args,1);
    switch($method_name) {
        case 'foo':
        case 'far':
        //case .....
            //write in log files
            break;

    }
    //THEN, RELAY THE CALL TO THE INITIAL METHOD
 }
}

    #"dynamic" A.php
class A extends Logger {
    public function foo($log_level, $bar) {
    parent::foo($log_level, $bar);
        echo ' // Hello there !';
    }

public function bar($foo) {
    echo " $ù$ùmezf$z !";
}
}

#"dynamic" B.php
class B extends Logger {
public function far($log_level, $boo) {
    parent::far($log_level, $bar);
    echo $boo;  
}
}

Большая проблема здесь заключается в том, чтобы преобразовать A и B в их «динамические» версии, как только анализатор XML завершит свою работу.

Идеальным было бы добиться этого, не изменяя код А и В вообще (я имею в виду, в файлах), или, по крайней мере, найти способ вернуться к их исходным версиям после завершения программы. *

Чтобы было ясно, я хочу найти наиболее правильный способ перехвата вызовов методов в PHP.

Что вы думаете об этом?

PS: и, конечно, не должно быть никакого ПОСЛЕДСТВИЯ для клиентского кода (не отличается, если перехват включен или нет).

Ответы [ 2 ]

0 голосов
/ 02 мая 2010

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

Метод здесь состоит в том, чтобы использовать промежуточный класс, который расширяет некоторый класс по умолчанию, который можно изменить (в этом случае на другой класс, также расширяющий стандарт).

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

<?php

/*
 * One of the following classes will be the superclass of the Child
 */

class Ancestor {
    function speak() {
        echo 'Ancestor <br />';
    }
}

class Mum extends Ancestor {
    function speak() {
        parent::speak();
        echo 'Mum <br />';
    }
}

class Dad extends Ancestor {
    function speak() {
        parent::speak();
        echo 'Dad <br />';
    }
}

/*
 * Decide on which class we wish to make the superclass of our Child
 */

$parentClass = null;

if (isset($_GET['parent'])) {
    $parentClass = $_GET['parent'];
    if (!class_exists($parentClass)) {
        $parentClass = "Ancestor";
    }
}

if (!is_null($parentClass)) {
    eval("class ChildParent extends $parentClass {};");
} else {
    class ChildParent extends Ancestor {};
}

if (class_exists('ChildParent')) {
class Child extends ChildParent
{
    function speak() {
        parent::speak();
        echo 'Child <br />';
    }
}
}

/*
 * Show what's going on
 */

echo '<a href="?">Either</a> | <a href="?parent=Mum">Mum</a> | <a href="?parent=Dad">Dad</a> <br />';

$child = new Child();
$child->speak();*
0 голосов
/ 23 апреля 2010

Вы могли бы использовать eval(), чтобы фактически определить классы, но вы должны быть очень осторожными .Функция eval() может быть очень опасной.

Примерно так:

$parentName = 'Bar';

eval('class Foo extends ' . $parentName . ' { }');

http://php.net/eval

...