PHP 事件监听器最佳实践实现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4471183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP Event-Listener best-practice implementation
提问by Y.H.
I am trying to create a CMS-like system in PHP. making it as modular and extendable as possible.
我正在尝试用 PHP 创建一个类似 CMS 的系统。使其尽可能模块化和可扩展。
Could someone offer me the best-practice scenario of creating a event-listener system in PHP (a very simplified version of Drupal system for example), creating hooks and implementing them in a short example would also be nice.
有人可以向我提供在 PHP 中创建事件侦听器系统的最佳实践方案(例如,Drupal 系统的一个非常简化的版本),创建挂钩并在一个简短的示例中实现它们也很好。
回答by ircmaxell
Well, there's really three different ways of doing this from an implementation perspective (note that these are OO design patterns, but you could implement them functionally or procedurally if you wanted to).
嗯,从实现的角度来看,确实有三种不同的方法可以做到这一点(请注意,这些是 OO 设计模式,但如果您愿意,您可以在功能上或程序上实现它们)。
1. Observer Pattern
1.观察者模式
You can implement the Observer Pattern. Basically, you'd have each thing that can raise events be a subject. Then the classes/code you want to listen binds to what it wants to listen to specifically. So let's say you have a controller called Foo
. If you wanted to listen to it, you could call $fooController->attach($observer);
. Then, whenever the controller wanted to say something, it would dispatch the event to all of the observers.
您可以实现观察者模式。基本上,您将可以引发事件的每件事都作为一个主题。然后,您想要收听的类/代码绑定到它想要特别收听的内容。因此,假设您有一个名为Foo
. 如果你想听它,你可以打电话给$fooController->attach($observer);
。然后,每当控制器想说些什么时,它就会将事件分派给所有观察者。
This is really well suited for a notification system (to extend what classes are doing). It's not as well suited for modifying the behavior of code in real time.
这非常适合通知系统(扩展类正在做什么)。它不太适合实时修改代码的行为。
2. Decorator PatternYou can also implement the Decorator Pattern. Basically, you take the object that you want to modify, and "wrap" it in a new object that does what you want to change. This is really well suited for modifying and extending the behavior (since you can selectively override functionality from the wrapped class).
2. 装饰模式你也可以实现装饰模式。基本上,您将要修改的对象“包装”在一个新对象中,该对象可以执行您想要更改的操作。这非常适合修改和扩展行为(因为您可以有选择地覆盖包装类的功能)。
This works very well if you have defined interfaces and expect objects to conform to them. If you don't have interfaces (or don't use them properly), most of what the decorator pattern can do for you will be lost.
如果您已经定义了接口并期望对象符合它们,这将非常有效。如果你没有接口(或者没有正确使用它们),装饰者模式可以为你做的大部分事情都会丢失。
Also note that this really isn't a way of doing events, it's a way of modifying object behavior.
另请注意,这实际上不是一种处理事件的方式,而是一种修改对象行为的方式。
3. Mediator Pattern
3. 中介模式
You could also use a Mediator. Basically, you'd have one global mediator that keeps track of your listeners. When you want to trigger an event, you send the event to the mediator. The mediator can then keep track of which listening objects want to receive that event, and pass the message along properly.
您也可以使用Mediator。基本上,您将拥有一个全局调解器来跟踪您的听众。当您想要触发一个事件时,您可以将事件发送给中介者。然后,中介器可以跟踪哪些侦听对象想要接收该事件,并正确传递消息。
This has the advantage of being central. Meaning multiple senders can send the same event, and to the listeners it doesn't make a difference who sent it...
这具有成为中心的优势。这意味着多个发件人可以发送相同的事件,而对于听众来说,谁发送它并没有什么区别......
回答by Codebeat
/*
Example 1:
event::bind('blog.post.create', function($args = array())
{
mail('[email protected]', 'Blog Post Published', $args['name'] . ' has been published');
});
Example 2:
event::trigger('blog.post.create', $postInfo);
*/
class event
{
public static $events = array();
public static function trigger($event, $args = array())
{
if(isset(self::$events[$event]))
{
foreach(self::$events[$event] as $func)
{
call_user_func($func, $args);
}
}
}
public static function bind($event, Closure $func)
{
self::$events[$event][] = $func;
}
}
回答by user187291
This is how i did it in a couple of projects
这就是我在几个项目中做到的
All objects are created with a constructor function instead of new
operator.
所有对象都是使用构造函数而不是new
运算符创建的。
$obj = _new('SomeClass', $x, $y); // instead of $obj = new SomeClass($x, $y);
this has many advantages compared to raw new
, from an event handling standpoint it's important that _new()
maintains a list of all created objects.
与 raw 相比,这有很多优点new
,从事件处理的角度来看,_new()
维护所有创建对象的列表很重要。
There's also a global function send($message, $params)
that iterates though this list and, if an object exposes a method "on_$message", calls this method, passing params:
还有一个全局函数send($message, $params)
可以遍历这个列表,如果一个对象公开了一个方法“on_$message”,调用这个方法,传递参数:
function send() {
$_ = func_get_args();
$m = "on_" . array_shift($_);
foreach($_all_objects as $obj)
if(method_exists($obj, $m))
call_user_func_array(array($obj, $m), $_);
}
So, for example, send('load')
will call on_load
method for every object that has it defined.
因此,例如,send('load')
将为on_load
每个定义了它的对象调用方法。