jrbarnard / hookable
一个使任何类可挂载的特质
Requires
- php: >=5.6.0
Requires (Dev)
- phpunit/phpunit: ^5.7
This package is auto-updated.
Last update: 2024-09-10 11:02:42 UTC
README
Hookable 是一个特质,任何 PHP 类都可以使用,它的目的是提供创建可挂载 '点' 的简单 API,并允许您在使用类外部或从扩展的子类中 '挂载' 到这些点。
这样做是为了能够在代码执行期间快速添加类似于事件的功能,同时提供非常灵活的 API。
例如
namespace App; use JRBarnard\Hookable\Hookable; class ToBeHooked { use Hookable; public function methodToBeHooked() { $data = ['item', 'another_item']; $someOtherVariable = 'Hello'; // We run a hook by key and pass through some data $this->runHook('hook_key', $data, $someOtherVariable); // Because we pass by reference, this variable may have been changed return $someOtherVariable; } } $toBeHooked = new ToBeHooked(); // Before we have registered the hook $return = $toBeHooked->methodToBeHooked(); // $return === 'Hello'; // Registering a hook on the key is as simple as specifying the key and the relevant callback. $toBeHooked->registerHook('hook_key', function($data, &$someOtherVariable){ if ($someOtherVariable === 'Hello') { $someOtherVariable = 'world'; } }); // After registering the hook $return = $toBeHooked->methodToBeHooked(); // $return === 'world';
内容
要求
Hookable 的最低 PHP 版本要求是 5.6,这是因为它使用了 可变参数函数。除此之外,不应有任何其他要求,如果您发现有任何要求,请记录为工单/提交拉取请求。
目前不支持 HHVM / Hack。
安装
Composer 是推荐的安装方法
composer require jrbarnard/hookable
但是,您也可以下载此仓库,解压缩它并将它包含到您的项目中。
使用
注册和运行钩子
此特质的主要用例之一是当您有一个非常通用的抽象/父类被广泛扩展,并且有时您想根据通用方法覆盖/运行操作,而不需要覆盖整个方法。
以下是一个示例
use JRBarnard\Hookable\Hookable; abstract class SomeClass { use Hookable; public function store(array $data) { $model = new Model(); $model->fill($data); $result = $model->save($result); $this->runHook('after_store', $data, $model); return $result; } }
class ChildClass extends SomeClass { public function __construct() { $this->registerHook('after_store', function(array $data, Model $model){ if ($model->isSpecial()) { // Do some sort of specific action for this child. // Perhaps send an email, log something etc. } }); // Same hook, will still run, but this will run after, unless we specify priorities. $this->registerHook('after_store', function(array $data, Model $model){ if ($model->isSpecial()) { // Do some sort of other action for this child. } }); } }
您也可以在外部对象上注册钩子
class SomeClass { use Hookable; } $someObject = new SomeClass(); $someObject->registerHook('some_hook', function(){ // Do something }) // You can also run hooks externally too (useful for testing, not sure if useful elsewhere) $someObject->runHook('some_hook');
您不需要直接传递闭包,您也可以使用数组语法引用特定的函数或类方法
// Standalone function function someFunction(){ // Do something } // Within a hookable classes constructor $this->registerHook('hook_key', ['someFunction']); // Class method class SomeClass { use Hookable; public function someMethod(){ // Do something } } $someObject = new SomeClass(); // Within a hookable classes constructor $this->registerHook('hook_key', ['someMethod', $someObject]);
运行钩子时传递的所有参数默认都是通过引用传递的,这允许我们(如果我们想更改传递的参数而不是对象)
class SomeClass { use Hookable; public function someMethod($array) { $this->runHook('hook_key', $array); return $array; } } $someObject = new SomeClass(); // Calling someMethod now will return the standard array $array = $someObject->someMethod(['test']); // $array will equal ['test'] $someObject->registerHook('hook_key', function(&$array){ $array = []; }); // Calling someMethod now will return the altered array as we have a hook $array = $someObject->someMethod(['test']); // $array will equal [];
您可以使用 runHook 传递任意数量的参数,它们将被解包并在您用 registerHook 指定的回调中作为参数可用
优先级
Hookable 还内置了优先级,当您注册一个钩子时,您可以在回调之后传递第三个参数,这将作为回调的优先级,这定义了它在调用顺序中的位置,数字越高,在调用顺序中运行得越晚
class SomeClass { use Hookable; } $someObject = new SomeClass(); $someObject->registerHook('test_priority', function(){ echo 'this will appear last'; }, 99); $someObject->registerHook('test_priority', function(){ echo 'this will appear first'; }, 1); $someObject->registerHook('test_priority', function(){ echo 'this will appear in the middle'; }, 50); // We would expect the output: // this will appear first // this will appear in the middle // this will appear last
如果您设置了两个具有相同键和相同优先级的钩子,它将使用它们注册的顺序,不会覆盖已设置的钩子。
检查和删除钩子
您可以通过在相关的可挂载对象上调用 hasHook 来检查是否存在钩子
class SomeClass { use Hookable; } $someObject = new SomeClass(); // Will be false $someObject->hasHook('test_has_hook'); $someObject->registerHook('test_has_hook', function(){ // Do something }); // Will be true $someObject->hasHook('test_has_hook');
如果您想删除对象上的钩子,可以使用 clearHooks 方法
class SomeClass { use Hookable; } $someObject = new SomeClass(); $someObject->registerHook('hook_one', function(){ // Do something }); $someObject->registerHook('hook_two', function(){ // Do something }); // This will remove all hooks registered to the name hook_one $someObject->clearHooks('hook_one'); // This will remove all hooks from the object, under all names $someObject->clearHooks();