我们可以通过使用PHP扩展函数在函数中注入更多行吗?

Ari*_*ona 7 php aop cross-cutting-concerns

我对我正在为自定义框架开发的事件系统有所了解.

想象一下像这样的伪函数.

class Test
{
    public function hi()
    {
        Event::add(__FUNCTION__ . 'is about to run.');
        return "hi";
    }
}
Run Code Online (Sandbox Code Playgroud)

想象一下,你需要为更多功能做同样的事情.(也许您想记录在运行时运行的函数,并希望将它们记录在单独的文件中.)

而不是这样做并手动将事件添加到函数中,我们可以做这样的事情吗?

class Test
{
    public function hi()
    {
        return "hi";
    }
}

// events.php (It's a pseudo code so may not work.)
// Imagine extend's purpose is to inject codes into target function

Event::bind('on', $className, $methodName, function() use ($className, $methodName) 
{
    return $className->$methodName->extend('before', Event::add(__FUNCTION__ . 'is about to run.'));
});
Run Code Online (Sandbox Code Playgroud)

我们的想法是注入hi()内部的函数Test class并注入我们通过extend外部传递的任何函数.'before'意味着注射必须在目标函数的第一线.

最后,事件和事件绑定将完全从函数中抽象出来.我希望能够在不改变功能的情况下绑定自定义的东西.

我有一种感觉,我们可以通过黑客攻击eval()或玩弄来做到这一点call_user_func().不过我不确定.使用eval()声音已经非常糟糕了.

我的问题是;

  1. 用PHP做可能吗?
  2. 它是否在OOP/OOP原则中有名称,以便我可以进一步阅读?
  3. 它有意义还是一个坏主意?

sec*_*tus 2

是的你可以。您可以使用GO使用AOP 适用于注释的AOP 框架。

例如,您想记录每个公共方法调用。而不是像这样添加到每个功能行。

namespace Acme;

class Controller
{
    public function updateData($arg1, $arg2)
    {
        $this->logger->info("Executing method " . __METHOD__, func_get_args()); 
        // ...
    }    
}
Run Code Online (Sandbox Code Playgroud)

您可以对 Acme 命名空间的所有类的所有公共方法使用一个方面,如下所示:

use Go\Aop\Aspect;
use Go\Aop\Intercept\MethodInvocation;
use Go\Lang\Annotation\Before;

    class LoggingAspect implements Aspect
    {
        /** @var null|LoggerInterface */
        protected $logger = null;

        /** ... */
        public function __construct($logger) 
        {
            $this->logger = $logger;
        }

        /**
         * Method that should be called before real method
         *
         * @param MethodInvocation $invocation Invocation
         * @Before("execution(public Acme\*->*())")
         */
        public function beforeMethodExecution(MethodInvocation $invocation)
        {
            $obj    = $invocation->getThis();
            $class  = is_object($obj) ? get_class($obj) : $obj;
            $type   = $invocation->getMethod()->isStatic() ? '::' : '->';
            $name   = $invocation->getMethod()->getName();
            $method = $class . $type . $name;

            $this->logger->info("Executing method " . $method, $invocation->getArguments());
        }
    }    
Run Code Online (Sandbox Code Playgroud)

它看起来更复杂,但更灵活。