jclaveau / php-deferred-callchain
注册一个稍后将在实例上应用的调用链
1.4.2
2019-11-19 11:23 UTC
Requires
- php: >=5.6.0
- jclaveau/php-fluent-trait: ^1.1
- jclaveau/php-visibility-violator: ^1.0
- symfony/polyfill-php72: ^1.12
Requires (Dev)
- phpunit/phpunit: >=5
README
这个类简单地提供了一种在目标(对象或原生值)可用之前定义流畅的方法、函数、数组访问调用的方式。一旦预期的目标可用,只需像调用函数一样调用链即可。
质量
概述
// having class MyClass { protected $name = 'unnamed'; public function setName($name) { $this->name = $name; return $this; } public function nameEntries() { return [ 'my_entry_1' => $this->name . " 1", 'my_entry_2' => $this->name . " 2", ]; } } // We can define some chained calls (none is executed) $doDummyCallsLater = DeferredCallChain::new_( MyClass::class ) // Targets must be MyClass instances ->nameEntries()['my_entry_2'] // access array entry ->strtoupper() // apply strtoupper() to it ; // do whatever we want // ... // Get your targets $myInstance1 = (new MyClass)->setName('foo'); $myInstance2 = (new MyClass)->setName('bar'); // Execute the callchain echo $doDummyCallsLater( $myInstance1 ); // => FOO 2 echo $doDummyCallsLater( $myInstance2 ); // => BAR 2
安装
php-deferred-callchain 可以通过 Composer 安装
composer require jclaveau/php-deferred-callchain
测试
测试位于 此处,可通过调用
./phpunit
用法
函数和链式构造
DeferredCallChain 可以以传统方式实例化
$nameRobert = (new DeferredCallChain(Human::class))->...
静态地
$nameRobert = DeferredCallChain::new_(Human::class)->...
或功能性地
$nameRobert = later(Human::class)->...
流畅的调用链
$nameRobert = DeferredCallChain::new_() ->setName('Muda') ->setFirstName('Robert') ; $mySubjectIMissedBefore = new Human; $robert = $nameRobert( $mySubjectIMissedBefore ); echo $robert->getFullName(); // => "Robert Muda" echo (string) $nameRobert; // => "(new JClaveau\Async\DeferredCallChain)->setName('Muda')->setFirstName('Robert')"
与数组一起工作
$getSubColumnValue = DeferredCallChain::new_() ['column_1'] ['sub_column_3'] ; $sub_column_3_value = $getSubColumnValue( [ 'column_1' => [ 'sub_column_1' => 'lalala', 'sub_column_2' => 'lololo', 'sub_column_3' => 'lilili', ], 'column_2' => [ 'sub_column_1' => 'lululu', 'sub_column_2' => 'lelele', 'sub_column_3' => 'lylyly', ], ] ); echo $sub_column_3_value; // => "lilili" echo (string) $getSubColumnValue; // => "(new JClaveau\Async\DeferredCallChain)['column_1']['sub_column_3']"
与原生类型和函数一起工作
上述功能使对对象方法的调用变得简单且异步,但当他们返回的不是对象时,流畅的语法必须停止,异步行为也必须停止。
基于 Daniel S Deboer 的工作 https://github.com/danielsdeboer/pipe,已添加了对链式函数调用的支持。
class MyClass { public function getString() { return 'string'; } } $upperifyMyClassString = DeferredCallChain::new_( MyClass::class ) ->getString() ->strtoupper(); echo $upperifyMyClassString( new MyClass ); // prints "STRING"
某些函数不使用流畅语法的主题作为第一个参数。在这种情况下,将 '$$' 作为参数提供,以便将其替换为主题。
class MyClass { public function getSentence() { return 'such a funny lib to implement'; } } $explodeMyClassSentence = DeferredCallChain::new_( MyClass::class ) ->getSentence() ->explode(' ', '$$'); $explodeMyClassSentence( new MyClass ); // returns ['such', 'a', 'funny', 'lib', 'to', 'implement']
指定链可以在哪个类、接口、类型或实例上调用
您可以强制您的调用链的目标
- 成为特定类的实例
$nameRobert = DeferredCallChain::new_(Alien::class) ->setName('Muda') ->setFirstName('Robert') ; $mySubjectIMissedBefore = new Human; $robert = $nameRobert( $mySubjectIMissedBefore ); // throws BadTargetClassException
- 实现特定接口
$getCount = DeferredCallChain::new_("\Traversable") ->count() ; $myCountableIMissedBefore = new CountableClass; // class implementing Countable // throws BadTargetInterfaceException
- 是特定原生类型
$nameRobert = DeferredCallChain::new_("array") ->setName('Muda') ->setFirstName('Robert') ; $mySubjectIMissedBefore = new Human; $robert = $nameRobert( $mySubjectIMissedBefore ); // throws BadTargetTypeException
- 是构造时提供的特定实例
$myTarget = new Human; $nameRobert = DeferredCallChain::new_($myTarget) ->setName('Muda') ->setFirstName('Robert') ; $robert = $nameRobert( new Human ); // throws TargetAlreadyDefinedException
引发异常的调用
由于调用可以在实际应用之前很久就进行,因此异常需要更多的调试信息以实现流畅的工作流程。为此,在 DeferredCallChain 执行期间抛出的每个异常消息中添加了一行,指向有问题的调用以及它的编码位置。
例如,消息为 一些用户代码抛出了一个异常
的异常将打印
An exception has been thrown by some user code
When applying (new JClaveau\Async\DeferredCallChain( <instance id> ))->previousSuccessfullCall()->buggyCall('Robert') defined at <file>:<line>
静态调用
静态调用可能很有用,特别是对于单例。由于一些技术原因,如 此处 所述,支持它的唯一方法是像普通方法(例如,使用 ->)一样调用它们,一旦我们知道它们不是普通方法,就将其视为静态方法。
later(MyModel::class)->getInstance()->myNormalGetter(); // or later($myModel)->getInstance()->myNormalGetter(); // like $myModel::getInstance()