定制 jclaveau/php-deferred-callchain 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jclaveau/php-deferred-callchain

Composer 安装命令:

composer require jclaveau/php-deferred-callchain

包简介

Register a chain of calls that will be applied on an instance later

README 文档

README

This class simply provides a way to define fluent chain of methods, functions, array access calls before having the target (object or native value) you wan't to apply it to. Once the expected targets are available, simply call the chain on them as if it was a function.

Latest Stable Version License Total Downloads contributions welcome

Quality

Tests codecov Scrutinizer Code Quality

Overview

// 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

Installation

php-deferred-callchain is installable via Composer

composer require jclaveau/php-deferred-callchain

Testing

Tests are located here and runnable by calling

./phpunit

Usage

Functionnal and chained construction

DeferredCallChain can be instanciated classically

$nameRobert = (new DeferredCallChain(Human::class))->...

Statically

$nameRobert = DeferredCallChain::new_(Human::class)->...

Or functionnaly

$nameRobert = later(Human::class)->...

Fluent call chain

$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')"

Working with arrays

$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']"

Working with native types and functions

The features above make calls to objects methods easy and async but when their result is not an object, the fluent syntax has to stop, and the async behavior also.

Based on Daniel S Deboer work https://github.com/danielsdeboer/pipe, support of chained function calls has been added.

class MyClass
{
    public function getString()
    {
        return 'string';
    }
}

$upperifyMyClassString = DeferredCallChain::new_( MyClass::class )
    ->getString()
    ->strtoupper();

echo $upperifyMyClassString( new MyClass ); // prints "STRING"

Some functions do not use the subject of the fluent syntax as first argument. In this case, giving '$$' as the parameter you want to be replaced by the subject.

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']

Specifying on which class, interface, type or instance, the chain is callable

You can force the target of your call chain to:

  • be an instance of a specific class
$nameRobert = DeferredCallChain::new_(Alien::class)
    ->setName('Muda')
    ->setFirstName('Robert')
    ;

$mySubjectIMissedBefore = new Human;
$robert = $nameRobert( $mySubjectIMissedBefore );

// throws BadTargetClassException
  • implement a specific interface
$getCount = DeferredCallChain::new_("\Traversable")
    ->count()
    ;

$myCountableIMissedBefore = new CountableClass; // class implementing Countable

// throws BadTargetInterfaceException
  • be of a specific native type
$nameRobert = DeferredCallChain::new_("array")
    ->setName('Muda')
    ->setFirstName('Robert')
    ;

$mySubjectIMissedBefore = new Human;
$robert = $nameRobert( $mySubjectIMissedBefore );

// throws BadTargetTypeException
  • be a specific instance given at construction
$myTarget = new Human;
$nameRobert = DeferredCallChain::new_($myTarget)
    ->setName('Muda')
    ->setFirstName('Robert')
    ;

$robert = $nameRobert( new Human );

// throws TargetAlreadyDefinedException

Calls provoking exceptions

As a call can be made far before it's effectivelly applied, exceptions need more debug information for a smooth workflow. To achieve that, a line is added to every exception message thrown during a DeferredCallChain execution, pointing to the buggy call and where it is coded.

For example, an exception having as message An exception has been thrown by some user code will print

An exception has been thrown by some user code
When applying (new JClaveau\Async\DeferredCallChain( <instance id> ))->previousSuccessfullCall()->buggyCall('Robert') defined at <file>:<line>

Static calls

Static calls can be useful, especially for singletons. For some technical reasons explained here, the only way to support it is to call them as normal methods (e.g. with -> ) and look for it as a static method once we know it doesn't exist as a regular one.

later(MyModel::class)->getInstance()->myNormalGetter();
// or
later($myModel)->getInstance()->myNormalGetter(); // like $myModel::getInstance()

jclaveau/php-deferred-callchain 适用场景与选型建议

jclaveau/php-deferred-callchain 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 6.97k 次下载、GitHub Stars 达 1, 最近一次更新时间为 2018 年 11 月 06 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「php」 「fluent」 「lazy」 「asynchronous」 「Chain」 「promise」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 jclaveau/php-deferred-callchain 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 jclaveau/php-deferred-callchain 我们能提供哪些服务?
定制开发 / 二次开发

基于 jclaveau/php-deferred-callchain 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 6.97k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 15
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-11-06