maxonfjvipon / elegant-elephant
EO风格的PHP原语小型库
Requires
- php: >=8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.13
- php-coveralls/php-coveralls: ^2.5
- phpstan/phpstan: ^1.8
- phpunit/phpunit: ^9.0
- rregeer/phpunit-coverage-check: ^0.3.1
- dev-master
- 4.12.0
- 4.11.1
- 4.11.0
- 4.10.0
- 4.9.0
- 4.8.0
- 4.7.2
- 4.7.1
- 4.7.0
- 4.6.0
- 4.5.0
- 4.4.2
- 4.4.1
- 4.4.0
- 4.3.2
- 4.3.1
- 4.3.0
- 4.2.0
- 4.1.0
- 4.0.0
- 3.1.0
- 3.0.0
- 2.1.0
- 2.0.0
- 1.0.0
- 0.3.1
- 0.2.2
- 0.2.1
- 0.1.1
- 0.0.4
- 0.0.3
- dev-docs/#78/logo-and-loc
- dev-#76-arr-reduced
- dev-#11-functions
- dev-#72-num-of-txt
- dev-asserts
- dev-readme
- dev-comparison-objects
This package is auto-updated.
Last update: 2024-09-11 13:22:14 UTC
README
ElegantElephant
ElegantElephant - EO风格的PHP原语小型库。灵感来源于Cactoos,由@yegor256创建。
动机
PHP被设计成一种过程式语言。后来PHP开始支持面向对象范式,但并不是真正的纯面向对象。我们得到了类,但我们仍然以过程式的方式使用它们。这个库强制你以真正的面向对象方式编写对象。
原则
入门
要求
- PHP >= 8.0
安装
composer require maxonfjvipon/elegant-elephant
片段
获取扁平数组
// The result will be [0, 1, 2, 2, 3, 3, 4, 5] (new ArrFlatten( [0, [1], [[2, 2], [3, 3]], [4, 5]], deep: 2 ))->asArray();
合并数组
/* * If user is admin, result array will contain permissions field * * [ * 'name' => ..., * 'age' => ..., * 'permissions' => [...], * 'projects' => [ * ['name' => ..., 'created_at' => ...], * [...], * ... * ] * ] */ (new ArrMerged( [ 'name' => $user->name, 'age' => $user->age, ], new ArrIf( $user->isAdmin(), ArrOf::func(fn () => [ 'permissions' => [...] ]) ), new ArrObject( 'projects', new ArrMapped( $projects, fn (Project $project) => [ 'name' => $project->name, 'created_at' => $project->created_at ] ) ) ))-asArray();
操作文本
// To lower case (new TxtLowered( TxtOf::str("Hello") ))->asString(); // To upper case (new TxtUpper("Hello"))->asString(); // Join texts, if $isAdmin === TRUE the result will be "Hello Admin" else "Hello username, what'up" (new TxtJoined([ "Hello ", // Conditional text, behaves like first text if condition is TRUE, like second otherwise new TxtCond( $isAdmin, "Admin" TxtOf::func(fn () => $user->name()) ), // Conditional text, behaves like first text if condition is TRUE, like empty string otherwise new TxtIf( !$isAdmin, ", what's up" ) ]))->asString();
从点(x y)的数组中获取前x个
$points = [['x' => 1, 'y' => 1], ['x' => 2, 'y' => 2], [...], ...]; NumOf::any( new AtKey( 'x', ArrOf::any( new FirstOf( $points ) ) ) )->asNumber(); // 1
获取过滤数组的长度
(new LengthOf( new ArrFiltered( [1, 2, 3, 4, 5, 6], fn (int $num) => $num > 3 ) ))->asNum(); // 3
商业项目中的复杂示例,没有明显的算法
(new AtKey( // 12. Get element by key "pump" from given array 'pump', ArrOf::any( // 11. Try to cast given element to array new FirstOf( // 10. Get first element of given array new ArrCond( // 9.1. If given sorted jockey pumps are not empty - take them new Not( new IsEmpty( $jockeyPumps = new ArrSticky( // 8. Cache given sorted jockey pumps new ArrSorted( // 7. Sort given mapped jockey pumps by "cost" key new ArrMapped( // 6. Map given jockey pumps new ArrCond( // 5.1. If optimized jockey pumps are not empty - take them new Not( new IsEmpty( $optimized = new ArrSticky( // 4. Cached optimized jockey pumps new ArrFiltered( // 3. Filter cached jockey pumps with optimization $dbPumps = new ArrSticky( // 2. Cache jockey pumps new ArrPumpsForJockeySelecting( // 1. Take jockey pumps from somewhere $request->jockey_series_ids, $request->accounting_rests ) ), $filterPump(threeFifths: true) ) ) ) ), $optimized, new ArrFiltered( // 5.2. If opmtimized jockey pumps are empty - filter jockey pumps without optimization $dbPumps, $filterPump(threeFifths: false) ) ), fn (Pump $pump) => [ 'pump' => $pump, 'cost' => $pump->priceByRates($rates), ] ), 'cost' ) ) ) ), $jockeyPumps, [['pump' => null]] // 9.2. or take [['pump' => null]] otherwise ), ) ), ))->value();
静态方法
由于PHP不允许在类中有多个构造函数,因此库中的一些类有公共静态方法,它们返回类的实例并替换次要构造函数。一些类有私有主要构造函数,以防止用户以错误的方式使用它们。
例如,看看具有私有构造函数但允许你通过几种静态方法创建Arr
对象实例的类ArrOf
。
use Maxonfjvipon\ElegantElephant\Arr\ArrOf; use Maxonfjvipon\ElegantElephant\Any\AnyOf; // From items ArrOf::items($item1, $item2, $item3)->asArray(); // [$item1, $item2, $item3] // From array ArrOf::array([1, 2, 3])->asArray(); // [1, 2, 3] // From Maxonfjvipon\ElegantElephant\Any ArrOf::any(AnyOf::arr(["Hello", "Jeff"]))->asArray(); // ["Hello", "Jeff"] // From callback ArrOf::func(fn () => ["Hello", "World"])->asArray(); // ["Hello", "World"]
如果你编写代码并发现你不能通过new
关键字创建对象 - 那么这个类肯定是有私有构造函数但公共静态方法来替换构造函数的类,所以尝试使用它们。
联合参数
几乎每个类都允许你将联合类型参数传递给构造函数。
例如,类TxtJoined
的行为像一个连接的字符串,并接受一个包含字符串、Txt
实例或它们的组合的array
或Arr
实例。
use Maxonfjvipon\ElegantElephant\Txt\TxtJoined; use Maxonfjvipon\ElegantElephant\Txt\TxtOf; use Maxonfjvipon\ElegantElephant\Arr\ArrOf; use Maxonfjvipon\ElegantElephant\Any\AnyOf; $joined1 = new TxtJoined([ TxtOf::str("Hello"), " ", TxtOf::any(AnyOf::str("Jeff")) ]); $joined2 = new TxtJoined( ArrOf::func(fn () => [ new TxtJoined(["Hello", " "]), "Jeff" ]) ); $joined1->asString() === $joined2->asString(); // "Hello Jeff" === "Hello Jeff" => TRUE
因此,当你编写代码时,你可能不必担心将参数转换为所需类型,例如将string
转换为Maxonfjvipon\ElegantElephant\Txt
。只需将你拥有的内容传递给对象,它知道如何处理它。
任何类型
具有任意(混合)类型值的任何事物。任何接口只有一个公共方法value
,它必须返回mixed
类型的值。
任何对象
测试
查看Any单元测试以更好地理解。
Arr
优雅的数组。Arr接口只有一个公共方法asArray()
,它必须返回一个数组。
扩展
你可以在自己的类中使用另一个接口 - IterableArr
,它扩展了Arr和\IteratorAggregate
。
\IteratorAggregate
允许您将扩展运算符 ...
应用于您的类。如果您想在类中使用扩展运算符而不实际调用 asArray()
方法,您应该让您的类实现 IterableArr
并使用 HasArrIterator
特性。该特性是扩展 Arr
类的默认实现。现在当您使用 ...
与您的类特性时,幕后会调用 asArray()
。
以下是一个更好的理解示例
use Maxonfjvipon\ElegantElephant\Arr; use Maxonfjvipon\ElegantElephant\Arr\IterableArr; use Maxonfjvipon\ElegantElephant\Arr\HasArrIterator; class MyArr implements Arr { /** code */ } class MyIterableArr implements IterableArr { use HasArrIterator; /** code */ } $arr = [...(new MyArr())->asArray()]; // good $arr = [...new MyIterableArr()]; // good, no actual calling asArray() $arr = [...(new MyIterableArr())->asArray()]; // good, but verbose $arr = [...new MyArr()]; // wrong
库中的所有 Arr
类都可以扩展。
Arr 类
测试
请参阅 Arr 单元测试 以获得更好的理解。
逻辑
优雅的布尔值。 Logic
接口只有一个方法 asBool()
,它必须返回 bool
。
Logic 类
测试
请参阅 Logic 单元测试 以获得更好的理解。
Num
优雅的数字。 Num
接口只有一个方法 asNumber()
,它必须返回 float
或 int
。
Num 类
测试
请参阅 Num 单元测试 以获得更好的理解。
Txt
优雅的字符串。 Txt
接口只有一个方法 asString()
,它必须返回 string
。
Txt->__toString()
还有一个接口,您可以在自己的类中使用 - StringableTxt
,它扩展了 Txt
和 \Stringable
。
\Stringable
允许您通过调用 __toString()
方法将您的类转换为字符串。因此,您可以使用 StringableTxt
接口和 TxtToString
辅助特性,它幕后调用 asString()
。
以下是一个更好的理解示例
use Maxonfjvipon\ElegantElephant\Txt\StringableTxt; use Maxonfjvipon\ElegantElephant\Txt\TxtToString; use Maxonfjvipon\ElegantElephant\Txt; class MyTxt implements Txt { /** code */ } class MyStringableTxt implements StringableTxt { use TxtToString; /** code */ } $txt = new MyTxt(); $stringableTxt = new MyStringableTxt(); echo $txt->asString(); // good echo $stringableTxt; // good, no actual calling asString() echo $stringableTxt->asString(); // good, but verbose echo $txt; // wrong
库中的所有 Txt
类都实现了 StringableTxt
。
Txt 类
测试
请参阅 Txt 单元测试 以获得更好的理解。
贡献
分支存储库,进行更改,发送拉取请求。为了避免挫折,在发送您的拉取请求之前,请运行
$ ./pre-push.sh
并确保没有错误。