sebastiaanluca / php-pipe-operator
使用任何方法对任何值进行方法链式调用(或流畅表达式)。
Requires
- php: ~8.1|~8.2
Requires (Dev)
- ext-mbstring: ~8.1|~8.2
- friendsofphp/php-cs-fixer: ^3.14
- phpunit/phpunit: ^9.6
README
使用任何方法对任何值进行方法链式调用(或流畅表达式)。
目录
需求
- PHP 8.1 或 8.2
如何安装
通过 Composer
composer require sebastiaanluca/php-pipe-operator
如何使用
基础
该包的基本原理是接受一个值并对它执行一个或多个操作。一个简单的例子
use SebastiaanLuca\PipeOperator\Pipe; Pipe::from('hello')->strtoupper()->get(); // "HELLO"
创建相同实例的几种替代方法
take('hello')->strtoupper()->get(); // "HELLO" pipe('hello')->strtoupper()->get(); // "HELLO"
当然,这并不很有用,因为你可以直接使用 strtoupper('hello')
并完成,但目标是为了使多方法调用值更易于阅读和编写
$subdomain = Pipe::from('https://blog.sebastiaanluca.com') ->parse_url() ->end() ->explode('.', PIPED_VALUE) ->reset() ->get(); // "blog"
请注意,与原始 RFC 相比,无需将初始值传递给接收值作为第一个参数且没有其他必需参数的方法。始终将上一个值作为第一个参数传递。实际上,以下两个示例都将有效
Pipe::from('hello')->strtoupper()->get(); // "HELLO" Pipe::from('hello')->strtoupper(PIPED_VALUE)->get(); // "HELLO"
相反,如果方法在上一个值之前接受例如一个设置,我们需要使用替换标识符(全局可用的 PIPED_VALUE
常量)手动设置它。此标识符可以放置在方法调用中的任何位置,它将被简单地替换为上一个值。
Pipe::from(['key' => 'value']) ->array_search('value', PIPED_VALUE) ->get(); // "key"
使用一等可调用语法(启用IDE自动完成)
由于 PHP 8.1,您可以使用一等可调用语法,或者简单地说一个匿名函数,将值通过管道传输。这启用了对方法的全局自动完成。
take('STRING') ->pipe(strtolower(...)) ->get() // "string"
或者使用参数
Pipe::from('https://sebastiaanluca.com/blog') ->pipe(parse_url(...)) ->end() ->pipe(substr(...), PIPED_VALUE, 3) ->pipe(strtoupper(...)) ->get(), // "OG"
使用闭包
有时标准方法不足以满足需求,您需要在处理过程中对值执行自定义操作。您可以使用闭包来实现这一点
Pipe::from('string') ->pipe(fn(string $value): string => 'prefixed-' . $value) ->get(); // "prefixed-string"
使用类方法
同样,使用类方法也可以实现(无论可见性如何)
class MyClass { public function __construct() { Pipe::from('HELLO') ->pipe($this)->lowercase() ->get(); // "hello" } /** * @param string $value * * @return string */ private function lowercase(string $value) : string { return mb_strtolower($value); } }
类方法替代方案
如果您不想使用内部管道代理并传递 $this
,您还有两种其他方法可以使用类方法。
使用一等可调用语法
class MyClass { public function __construct() { Pipe::from('HELLO') ->pipe($this->lowercase(...)) ->get(); // "hello" } /** * @param string $value * * @return string */ public function lowercase(string $value) : string { return mb_strtolower($value); } }
使用数组(仅限公共方法)
class MyClass { public function __construct() { Pipe::from('HELLO') ->pipe([$this, 'lowercase']) ->get(); // "hello" } /** * @param string $value * * @return string */ public function lowercase(string $value) : string { return mb_strtolower($value); } }
通过解析可调用方法到闭包
use Closure; class MyClass { public function __construct() { Pipe::from('HELLO') ->pipe(Closure::fromCallable([$this, 'lowercase'])) ->get(); // "hello" } /** * @param string $value * * @return string */ private function lowercase(string $value) : string { return mb_strtolower($value); } }
它解决了什么问题?
此包基于Sara Golemon(2016)的管道操作 RFC,她将问题解释为
PHP OOP 中的一种常见模式是使用方法链式调用,或称为“流畅表达式”。 [...] 这对于为流畅调用而设计的 OOP 类来说效果不错,但对于无法或至少不必要地困难地适应这种使用风格的非流畅类来说,对于功能接口来说尤其困难。
在看到这个提议后,我也博客中提到了它。
一个简单的例子
比如说你想从一个 URL 中获取子域名,你最终得到的东西可能像这样
$subdomain = 'https://blog.sebastiaanluca.com/'; $subdomain = parse_url($subdomain, PHP_URL_HOST); $subdomain = explode('.', $subdomain); $subdomain = reset($subdomain); // "blog"
当然,这可以工作,但它的可读性和重复性都很差。
另一种写法
相同的结果,不同的风格
$subdomain = explode('.', parse_url('https://blog.sebastiaanluca.com/', PHP_URL_HOST))[0]; // "blog"
这可能是最糟糕的解决方案,因为它要求你从中间开始阅读,逐渐向外扩展到外层方法,并不断切换。方法越多,变种越多,就越难理解正在发生的事情。
更多关于该问题的示例
请参阅 Sara的RFC 以获取更复杂和实际应用的示例。
注意
虽然这个包在将管道操作符引入PHP方面做出了很好的尝试,但它不幸地没有提供链式方法自动补全。为了实现这一点,我们需要真正的解决方案,所以请大声呼吁并让负责的人投票 支持 Sara的RFC!
许可证
本软件包遵循MIT许可证(MIT)。请参阅LICENSE 获取更多信息。
变更日志
请参阅 CHANGELOG 了解最近的变化。
测试
composer install
composer test
贡献
请参阅 CONTRIBUTING 和 CONDUCT 了解详细信息。
安全
如果您发现任何与安全相关的问题,请通过电子邮件 hello@sebastiaanluca.com 而不是使用问题跟踪器。
致谢
关于
我叫Sebastiaan,是一名自由职业的Laravel开发者,专门从事构建定制Laravel应用程序。查看我的 作品集 获取更多信息,查看我的 博客 获取最新技巧和窍门,以及我的其他 软件包 以启动您的下一个项目。
您有一个需要指导的项目吗?请通过电子邮件发送到 hello@sebastiaanluca.com!