PHP修饰符是否等同于PHP?

问题描述 投票:11回答:5

我希望能够用另一个函数包装一个PHP函数,但保留其原始名称/参数列表不变。

例如:

function A() {
    print "inside A()\n";
}

function Wrap_A() {
    print "Calling A()\n";
    A();
    print "Finished calling A()\n";
}

// <--- Do some magic here (effectively "A = Wrap_A")

A();

输出:

Calling A()
inside A()
Finished calling A()
php python function decorator wrapper
5个回答
8
投票

显然runkit可能是help you

此外,您始终可以通过OO方法执行此操作。将原始乐趣放入一个类中,并将装饰器放入扩展类中。实例化并继续。


3
投票

这是我从php中的python模仿装饰器的方法。

function call_decorator ($decorator, $function, $args, $kwargs) {

    // Call the decorator and pass the function to it
    $decorator($function, $args, $kwargs);
}

function testing ($args, $kwargs) {
    echo PHP_EOL . 'test 1234' . PHP_EOL;
}

function wrap_testing ($func, $args, $kwargs) {

    // Before call on passed function
    echo 'Before testing';

    // Call the passed function
    $func($args, $kwargs);

    // After call on passed function
    echo 'After testing';
}

// Run test
call_decorator('wrap_testing', 'testing');

输出:

Before testing
testing 1234
After testing

通过此实现,您还可以使用匿名函数执行类似的操作:

// Run new test
call_decorator('wrap_testing', function($args, $kwargs) {
    echo PHP_EOL . 'Hello!' . PHP_EOL;
});

输出:

Before testing
Hello!
After testing

最后,如果您愿意的话,甚至可以做这样的事情。

// Run test
call_decorator(function ($func, $args, $kwargs) {
    echo 'Hello ';
    $func($args, $kwargs);
}, function($args, $kwargs) {
    echo 'World!';
});

输出:

Hello World!

通过上述结构,可以根据需要将变量传递给内部函数或包装器。这是带有匿名内部函数的实现:

$test_val = 'I am accessible!';

call_decorator('wrap_testing', function($args, $kwargs){
    echo $args[0];
}, array($test_val));

如果没有匿名函数,它将完全相同:

function test ($args, $kwargs) {
    echo $kwargs['test'];
}

$test_var = 'Hello again!';

call_decorator('wrap_testing', 'test', array(), array('test' => $test_var));

最后,如果您需要在包装器或包装器中修改变量,则只需通过引用传递变量。

无参考:

$test_var = 'testing this';
call_decorator(function($func, $args, $kwargs) {
    $func($args, $kwargs);
}, function($args, $kwargs) {
    $args[0] = 'I changed!';
}, array($test_var));

输出:

testing this

参考:

$test_var = 'testing this';
call_decorator(function($func, $args, $kwargs) {
    $func($args, $kwargs);
}, function($args, $kwargs) {
    $args[0] = 'I changed!';

// Reference the variable here
}, array(&$test_var));

输出:

I changed!

这就是我现在所拥有的,在很多情况下这是非常有用的,如果需要,甚至可以多次包装它们。


1
投票

也许您正在寻找call_user_func_array

call_user_func_array

自PHP 5.3起,您甚至可以说:

function wrapA() {
  $args = func_get_args();
  return call_user_func_array('A', $args);
}

编辑完问题后,我会说,不,这不可能,但是有一些方法,请参见此问题:return call_user_func_array('A', func_get_args());


1
投票

您无法使用PHP中的函数执行此操作。在其他动态语言(例如Perl和Ruby)中,您可以重新定义先前定义的函数,但是当您尝试这样做时,PHP会引发致命错误。

在5.3中,您可以创建how to implement a decorator in PHP?并将其存储在变量中:

anonymous function

或者,您可以使用传统的装饰器模式和/或工厂来代替类。


0
投票

您可以使用面向方面的编程。但是您需要一些支持AOP的框架。

例如Symfony。这是AOP for php的实现之一<?php $my_function = function($args, ...) { ... }; $copy_of_my_function = $my_function; $my_function = function($arg, ...) { /* Do something with the copy */ }; ?>

还有Nette框架(我使用https://github.com/goaop/goaop-symfony-bundle

原则上它是这样的:假设您要在用户未登录并尝试访问某些方法的情况下引发异常。

这仅仅是“ fictive”代码以显示其工作方式。

您有类似的方面方法:

this one

然后您可以在服务中使用注释/** @AroundMethod(annotataion="isUserLogged()") */ public function checkUser(Method $method) { if ($this->user->isLogged()) { return $method->call(); } else { throw new \Exception('User must be logged'); } } ,该注释可能已在某些DI容器中注册。

@isUserLogged
© www.soinside.com 2019 - 2024. All rights reserved.