rodnaph / singer
PHP 线程
Requires
- php: >=5.3.3
Requires (Dev)
- phpunit/phpunit: 3.7.*
README
PHP 提供了许多实用工具,但以可理解的方式调用它们通常会导致代码混乱。Singer 通过允许通过函数/方法“线程”结果来清理这些混乱,从而提供可读的业务逻辑链。
线程
在这里,“线程”不是指操作系统线程,而是指将一个函数/方法的输出结果传递到下一个函数的线程。使用 PHP,我们通常需要将函数调用的结果分配给临时变量(以便传递给下一个函数)...
$values = array(1, 2, 3); $evenValues = array_filter($values, $even); $incdValues = array_map($inc, $evenValues);
或者我们嵌套我们的函数调用,以便结果直接进入下一个...
$result = array_map( $inc, array_filter( $values, $even ) );
这是一个非常简单的例子,数据处理的步骤越多,情况就越糟糕。
Singer 使用方法
以上是简单的例子,以下是使用 Singer 重新编写的方法。
use Singer\Thread as T; // standard version $values = array(1, 2, 3); $evenValues = array_filter($values, $even); $incdValues = array_map($inc, $evenValues); // singer version T::singer($values) ->filter($even) ->map($inc) ->value();
所以,Singer 允许将函数连接起来,这样我们的代码就不需要处理临时变量来控制数据的流程。与追踪变量分配和将其反馈到其他函数相比,处理流程更为明显。
线程第一个/最后一个
Singer 允许几种不同的线程方法。默认方法是“线程最后一个”- 这意味着每个函数的结果都作为下一个函数的最后一个参数传递。
你可以通过将数据“线程”到第一个参数来线程数据,这被称为“线程第一个”- 这意味着每个函数的结果都作为链中的下一个函数的第一个参数传递。
您可以使用 threadFirst 和 threadLast 方法在这些之间切换,如下所示。
function array_last($array) { return $array[count($array) - 1]; } T::create(array(1,2,3)) ->threadLast() ->array_last() ->threadFirst() ->range(10) ->value(); // array(3,4,5,6,7,8,9,10);
在这个例子中,我们调用自己的 array_last 函数,也调用核心 PHP 函数 range。
线程最后一个适用于需要数组(如 array_map 之类的“序列”函数)的函数,而线程第一个适用于操作单个值的函数(例如 str_to_upper)。
线程到第 n 个
您还可以使用 threadNth 将线程到任意位置。
T::create($x) ->threadNth(3) ->someFunc($one, $two) ->value();
这使用 1 为基数的索引。因此 1 是第一个参数位置,2 是第二个,依此类推...
命名空间
默认情况下,通过线程器调用函数时,它会在根命名空间中查找这些函数。这对于标准库函数来说没问题。要更改命名空间,请使用 inNamespace 方法。
T::create('foo bar baz') ->threadFirst() ->inNamespace('String\Utils') ->sentenceCase() ->inNamespace('Word\Utils') ->countWords() ->value(); // 3
同样,您可以随意更改命名空间范围。
静态/对象方法
到目前为止,我们只调用普通函数,但您也可以调用类和实例方法。
T::create('foo') ->onClass('Some\Static\Class') ->the_method() // Class::the_method() ->onObject($foo) ->bar() // $foo->bar() ->value();
和往常一样,这些方法可以在执行时按需包含。
两个构造函数
创建 Singer 对象有两种构造函数,第一个是 create
T::create($initial);
这将创建一个使用根命名空间的线程对象,并使用 thread last。您可以直接使用它来调用所有 PHP 标准库函数。
第二个构造函数是 singer
T::singer($initial);
它创建一个使用 thread last 的线程对象,在 实用程序命名空间 中。此命名空间提供了一组旨在提供比 PHP 更干净、更一致 API 的函数。
T::singer(array(1,2,3)) ->map($inc) ->filter($even) ->reduce($toTotal, 0) ->value();
这两种方法都会创建相同的线程器对象,只是默认命名空间不同。您可以使用上面所有的选项来切换它们。
调试中...
在不同点检查当前正在处理的上下文值可能很有用。为此,您可以使用 debug 函数。
T::create(array(1, 2, 3)) ->map($inc) ->debug() // will print_r(array(2, 3, 4)) and exit ->filter($odd) ->value();
如果您不想使用默认的 print_r,则可以传递自己的函数,该函数将接受上下文作为参数。
T::create(array(1, 2, 3)) ->map($inc) ->debug(function($context) { ... });
这不像是...
链式调用?不,链式调用是在同一个对象上调用多个方法的技巧。
Undercore.js 链式调用?更像是这个,但是可以控制先/后和第 n 个。
Singer 不做什么?
Singer 在您使用更功能性的方式编写 PHP 时表现最佳,如果您使用(我认为)实用程序命名空间中的函数,它的工作效果相当好。
虽然它支持在对象上调用方法,但如果您发现自己经常这样做,那么您可能应该考虑这真的是最易懂的做法(因为您的逻辑可能分散在不同的对象上...或者类似的东西...)。
安装
要安装 Singer,您可以从 Github 克隆/下载,或者通过 Composer 安装。
关于
Singer 的理念是尽可能鼓励将功能分离成最孤立的组件。然后允许您在最后一刻轻松地组合这些片段。
如果您想贡献想法或代码,只需打开一个问题或拉取请求即可。