【问题标题】:Can we inject some more lines in a function by extending it with PHP?我们可以通过用 PHP 扩展函数来在函数中注入更多行吗?
【发布时间】:2013-05-19 21:11:54
【问题描述】:

我对正在为我的自定义框架开发的事件系统有一个想法。

想象一下这样的伪函数。

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

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

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

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.'));
});

这个想法是注入hi()函数,它在Test class内部,并从外部注入我们传入extend函数的任何东西。 'before' 表示注入必须在目标函数的第一行。

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

我有一种感觉,我们可以通过使用 eval() 或玩弄 call_user_func() 来做到这一点。不过,我不确定。使用 eval() 听起来已经很糟糕了。

我的问题是;

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

【问题讨论】:

  • 我认为使用类的全部意义在于重用它们?
  • 不确定。也许是代理?
  • Dependency Injection?在设计模式方面,Fowler 总是一个很好的资源。 martinfowler.com/articles/injection.html避免eval
  • 这对call_user_func 来说绝对可行,尽管配置起来可能很尴尬。请注意,这种“装饰”风格在许多编程范式和框架中都有使用——但您应该注意性能问题。为每个函数调用写入文件可能会杀死您编写的任何程序。
  • @ficuscr 不,他说的是 [ 装饰器模式 | en.wikipedia.org/wiki/Decorator_pattern]

标签: php aop cross-cutting-concerns


【解决方案1】:

是的,你可以。您可以使用GO! AOP framework 使用AOP,它适用于注释。

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

namespace Acme;

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

您可以对 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());
        }
    }    

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-16
    • 2011-11-18
    • 2013-07-10
    • 1970-01-01
    • 2015-11-09
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    相关资源
    最近更新 更多