承接 aura/dispatcher 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

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

aura/dispatcher

Composer 安装命令:

composer require aura/dispatcher

包简介

Creates objects from a factory and invokes methods using named parameters; also provides a trait for invoking closures and object methods with named parameters.

README 文档

README

Provides tools to map arbitrary names to dispatchable objects, then to dispatch to those objects using named parameters. This is useful for invoking controller and command objects based on path-info parameters or command line arguments, for dispatching to closure-based controllers, and for building dispatchable objects from factories.

Foreword

Installation

This library requires PHP 5.4 or later; we recommend using the latest available version of PHP as a matter of principle. It has no userland dependencies.

It is installable and autoloadable via Composer as aura/dispatcher.

Alternatively, download a release or clone this repository, then require or include its autoload.php file.

Quality

Scrutinizer Code Quality Code Coverage Build Status

To run the unit tests at the command line, issue phpunit at the package root. (This requires PHPUnit to be available as phpunit.)

This library attempts to comply with PSR-1, PSR-2, and PSR-4. If you notice compliance oversights, please send a patch via pull request.

Community

To ask questions, provide feedback, or otherwise communicate with the Aura community, please join our Google Group, follow @auraphp on Twitter, or chat with us on #auraphp on Freenode.

Getting Started

Overview

First, an external routing mechanism such as Aura.Router or a micro-framework router creates an array of parameters. (Alternatively, the parameters may be an object that implements ArrayAccess).

The parameters are then passed to the Dispatcher. It examines them and picks an object to invoke with those parameters, optionally with a method determined by the parameters.

The Dispatcher then examines the returned result from that first invocation. If the result is itself a dispatchable object, the Dispatcher will recursively dispatch the result until something other than a dispatchable object is returned.

When a non-dispatchable result is returned, the Dispatcher stops recursion and returns the non-dispatchable result.

Closures and Invokable Objects

First, we tell the Dispatcher to examine the controller parameter to find the name of the object to dispatch to:

<?php
use Aura\Dispatcher\Dispatcher;

$dispatcher = new Dispatcher;
$dispatcher->setObjectParam('controller');
?>

Next, we set a closure object into the Dispatcher using setObject():

<?php
$dispatcher->setObject('blog', function ($id) {
    return "Read blog entry $id";
});
?>

We can now dispatch to that closure by using the name as the value for the controller parameter:

<?php
$params = [
    'controller' => 'blog',
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

The same goes for invokable objects. First, define a class with an __invoke() method:

<?php
class InvokableBlog
{
    public function __invoke($id)
    {
        return "Read blog entry $id";
    }
}
?>

Next, set an instance of the object into the Dispatcher:

<?php
$dispatcher->setObject('blog', new InvokableBlog);
?>

Finally, dispatch to the invokable object (the parameters and logic are the same as above):

<?php
$params = [
    'controller' => 'blog',
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

Object Method

We can tell the Dispatcher to examine the params for a method to call on the object. This method will take precedence over the __invoke() method on an object, if such a method exists.

First, tell the Dispatcher to examine the value of the action param to find the name of the method it should invoke.

<?php
$dispatcher->setMethodParam('action');
?>

Next, define the object we will dispatch to; note that the method is read() instead of __invoke().

<?php
class Blog
{
    public function read($id)
    {
        return "Read blog entry $id";
    }
}
?>

Then, we set the object into the Dispatcher ...

<?php
$dispatcher->setObject('blog', new Blog);
?>

... and finally, we invoke the Dispatcher; we have added an action parameter with the name of the method to invoke:

<?php
$params = [
    'controller' => 'blog',
    'action' => 'read',
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

Embedding Objects in Parameters

If you like, you can place dispatchable objects directly in the parameters. (This is often how micro-framework routers work.) For example, let's put a closure into the controller parameter; when we invoke the Dispatcher, it will invoke that closure.

<?php
$params = [
    'controller' => function ($id) {
        return "Read blog entry $id";
    },
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

The same is true for invokable objects ...

<?php
$params = [
    'controller' => new InvokableBlog,
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

... and for object-methods:

<?php
$params = [
    'controller' => new Blog,
    'action' => 'read',
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

Recursion and Lazy Loading

The Dispatcher is recursive. After dispatching to the first object, if that object returns a dispatchable object, the Dispatcher will re-dispatch to that object. It will continue doing this until the returned result is not a dispatchable object.

Let's turn the above example of an invokable object in the Dispatcher into a lazy-loaded instantiation. All we have to do is wrap the instantiation in another dispatchable object (in this example, a closure). The benefit of this is that we can fill the Dispatcher with as many objects as we like, and they won't get instantiated until the Dispatcher calls on them.

<?php
$dispatcher->setObject('blog', function () {
    return new Blog;
});
?>

Then we invoke the dispatcher with the same params as before.

<?php
$params = [
    'controller' => 'blog',
    'action' => 'read',
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

What happens is this:

  • The Dispatcher finds the 'blog' dispatchable object, sees that it is a closure, and invokes it with the params.

  • The Dispatcher examines the result, sees the result is a dispatchable object, and invokes it with the params.

  • The Dispatcher examines that result, sees that it is not a callable object, and returns the result.

Sending The Array Of Params Directly

Sometimes you will want to send the entire array of parameters directly to the object method or closure, as opposed to matching parameter keys with function argument names. To do so, name a key in the parameters array for the argument name that will receive them, and then set the parameters array into itself using that name. If may be easier to do this by reference, or by copy, depending on your needs.

<?php
// a dispatchable closure that takes an array of params directly,
// not the individual params by keys matching argument names
$dispatcher->setObject('blog', function ($params) {
    return "Read blog entry {$params['id']}"
});

// the initial params
$params = [
     'controller' => 'blog',
     'action' => 'read',
     'id' => 88,
];

// set a params reference into itself; this corresponds with the
// 'params' closure argument
$params['params'] =& $params;

// dispatch
$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

Refactoring To Architecture Changes

The Dispatcher is built with the idea that some developers may begin with a micro-framework architecture, and evolve over time toward a full-stack architecture.

At first, the developer uses closures embedded in the params:

<?php
$dispatcher->setObjectParam('controller');

$params = [
    'controller' => function ($id) {
        return "Read blog entry $id";
    },
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

After adding several controllers, the developer is likely to want to keep the routing configurations separate from the controller actions. At this point the developer may start putting the controller actions in the Dispatcher:

<?php
$dispatcher->setObject('blog', function ($id) {
    return "Read blog entry $id!";
});

$params = [
    'controller' => 'blog',
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

As the number and complexity of controllers continues to grow, the developer may wish to put the controllers into their own classes, lazy-loading along the way:

<?php
class Blog
{
    public function __invoke($id)
    {
        return "Read blog entry $id";
    }
}

$dispatcher->setObject('blog', function () {
    return new Blog;
});

$params = [
    'controller' => 'blog',
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

Finally, the developer may collect several actions into a single controller, keeping related functionality in the same class. At this point the developer should call setMethodParam() to tell the Dispatcher where to find the method to invoke on the dispatchable object.

<?php
class Blog
{
    public function browse()
    {
        // ...
    }

    public function read($id)
    {
        return "Read blog entry $id";
    }

    public function edit($id)
    {
        // ...
    }

    public function add()
    {
        // ...
    }

    public function delete($id)
    {
        // ...
    }
}

$dispatcher->setMethodParam('action');

$dispatcher->setObject('blog', function () {
    return new Blog;
});

$params = [
    'controller' => 'blog',
    'action' => 'read',
    'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

Construction-Based Configuration

You can set all dispatchable objects, along with the object parameter name and the method parameter name, at construction time. This makes it easier to configure the Dispatcher object in a single call.

<?php
$object_param = 'controller';
$method_param = 'action';
$objects = [
    'blog' => function () {
        return new BlogController;
    },
    'wiki' => function () {
        return new WikiController;
    },
    'forum' => function () {
        return new ForumController;
    },
];

$dispatcher = new Dispatcher($objects, $object_param, $method_param);
?>

Intercessory Dispatch Methods

Sometimes your classes will have an intercessory method that picks an action to run, either on itself or on another object. This package provides an InvokeMethodTrait to invoke a method on an object using named parameters. (The InvokeMethodTrait honors protected and private scopes.)

<?php
use Aura\Dispatcher\InvokeMethodTrait;

class Blog
{
    use InvokeMethodTrait;

    public function __invoke(array $params)
    {
        $action = isset($params['action']) ? $params['action'] : 'index';
        $method = 'action' . ucfirst($action);
        return $this->invokeMethod($this, $method, $params);
    }

    protected function actionRead($id = null)
    {
        return "Read blog entry $id";
    }
}
?>

You can then dispatch to the object as normal, and it will determine its own logical flow.

<?php
$dispatcher->setObject('blog', function () {
    return new Blog;
});

$params = [
     'controller' => 'blog',
     'action' => 'read',
     'id' => 88,
];

$result = $dispatcher($params); // or call __invoke() directly
echo $result; // "Read blog entry 88"
?>

aura/dispatcher 适用场景与选型建议

aura/dispatcher 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 98.18k 次下载、GitHub Stars 达 36, 最近一次更新时间为 2013 年 09 月 23 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

围绕 aura/dispatcher 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

  • 总下载量: 98.18k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 36
  • 点击次数: 32
  • 依赖项目数: 3
  • 推荐数: 0

GitHub 信息

  • Stars: 36
  • Watchers: 13
  • Forks: 8
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-2-Clause
  • 更新时间: 2013-09-23