unicorn-fail/php-option
Composer 安装命令:
composer require unicorn-fail/php-option
包简介
A highly extensible replacement for [phpoption/phpoption] with `TypedOption` support.
README 文档
README
A highly extensible replacement for phpoption/phpoption with
TypedOptionsupport.
An Option is intended for cases where you sometimes might return a value
(typically an object), and sometimes you might return no value (typically null)
depending on arguments, or other runtime factors.
Often times, you forget to handle the case where no value is returned. Not intentionally of course, but maybe you did not account for all possible states of the system; or maybe you indeed covered all cases, then time goes on, code is refactored, some of these your checks might become invalid, or incomplete. Suddenly, without noticing, the no value case is not handled anymore. As a result, you might sometimes get fatal PHP errors telling you that you called a method on a non-object; users might see blank pages, or worse.
On one hand, an Option forces a developer to consciously think about both cases
(returning a value, or returning no value). That in itself will already make your code more
robust. On the other hand, the Option also allows the API developer to provide
more concise API methods, and empowers the API user in how he consumes these methods.
📦 Installation
This project can be installed via Composer:
$ composer require unicorn-fail/php-option
Basic Usage
Using Option in your API
<?php use UnicornFail\PhpOption\None; use UnicornFail\PhpOption\Some; class MyRepository { public function findSomeEntity($criteria) { if (null !== $entity = $this->entityManager->find($criteria)) { return Some::create($entity); } // Use a singleton for the None case (it's statically cached for performance). return None::create(); } }
If you are consuming an existing library, you can also use a shorter version
which by default treats null as None, and everything else as Some case:
After:
<?php use UnicornFail\PhpOption\Option; class MyRepository { public function findSomeEntity($criteria) { return Option::create($this->entityManager->find($criteria)); // Or, if you want to change the none value to false for example: return Option::create($this->em->find($criteria), ['noneValue' => false]); } }
Case 1: always require an Entity when invoking code
$entity = $repo->findSomeEntity($criteria)->get(); // Returns an Entity, or throws exception.
Case 2: fallback to default value if not available
$entity = $repo->findSomeEntity($criteria)->getOrElse(new Entity); // Or, if you need to lazily create the entity. $entity = $repo->findSomeEntity($criteria)->getOrCall(function() { return new Entity; });
No More Boiler Plate Code
Before:
$entity = $this->findSomeEntity(); if ($entity === null) { throw new NotFoundException(); } return $entity->name;
After:
return $this->findSomeEntity()->get()->name;
No more control flow exceptions
Before:
try { $entity = $this->findSomeEntity(); } catch (NotFoundException $ex) { $entity = new Entity; }
After:
$entity = $this->findSomeEntity()->getOrElse(new Entity);
Concise null handling
Before:
$entity = $this->findSomeEntity(); if ($entity === null) { return new Entity; } return $entity;
After:
return $this->findSomeEntity()->getOrElse(new Entity);
Chaining multiple alternative Options
If you need to try multiple alternatives, the orElse method allows you to
do this very elegantly.
Before:
$entity = $this->findSomeEntity(); if ($entity === null) { $entity = $this->findSomeOtherEntity(); if ($entity === null) { $entity = $this->createEntity(); } } return $entity;
After:
return $this->findSomeEntity() ->orElse($this->findSomeOtherEntity()) ->orElse($this->createEntity());
The first option which is non-empty will be returned. This is especially useful with lazily evaluated options.
Lazily evaluated Options
The above example has a flaw where the option chain would need to evaluate all options when the method is called. This creates unnecessary overhead if the first option is already non-empty.
Fortunately, this can be easily solved by using LazyOption which takes a callable
that will be invoked only if necessary:
use UnicornFail\PhpOption\LazyOption; return $this->findSomeEntity() ->orElse(LazyOption::create([$this, 'findSomeOtherEntity'])) ->orElse(LazyOption::create([$this, 'createEntity']));
Typed options
In cases where you need a specific PHP type returned (e.g. string, boolean, number, etc.) the TypedOption class
may provide you with more flexibility:
Before:
// ?coords=32:43,35:22,94:33,95:34 $coordsStr = !!(isset($_GET['coords']) ? $_GET['coords'] : ''); $coords = $coordsStr ? array_map('trim', explode(',', $coordsStr)) : []; foreach ($coords as $coord) { list ($x, $y) = array_map('trim', explode(':', $coord)); $this->doSomething($x, $y); }
After:
use UnicornFail\PhpOption\TypedOption; // Automatically parsed by the SomeArray typed option. // ?coords=32:43,35:22,94:33,95:34 $items = TypedOption::pick($_GET, 'coords', ['keyDelimiter' => ':'])->getOrElse([]); foreach ($items as $x => $y) { $this->doSomething($x, $y); }
📓 API Documentation
Official and extensive API documentation coming soon (PRs are welcome).
🏷️ Versioning
SemVer is followed closely. Minor and patch releases should not introduce breaking changes to the codebase.
This project's initial release will start at version 1.6.0 to stay in line with existing phpoption/phpoption releases.
🛠️ Support & Backward Compatibility
Version <1.6.0
- This project will not patch any bugs, address any security related issues, or make another release.
Please upgrade, it should be as simple as:
$ composer remove phpoption/phpoption $ composer require unicorn-fail/php-option
Version >=1.6.0 <2.0.0
- This project will keep backward compatibility with phpoption/phpoption and continue running the original tests to ensure previous namespaces and implementation are still functional.
- The following classes are automatically registered as aliases so existing code should still remain functional (see known caveats below):
PhpOption\LazyOption=>UnicornFail\PhpOption\LazyOptionPhpOption\None=>UnicornFail\PhpOption\NonePhpOption\Option=>UnicornFail\PhpOption\OptionPhpOption\Some=>UnicornFail\PhpOption\Some
- The following methods have been deprecated, use their replacements instead:
Option::ensure()=>Option::create()Option::fromValue()=>Option::create()Option::fromArraysValue()=>Option::pick()Option::fromReturn()=>Option::create()$option->ifDefined()=>$option->forAll()
- Known caveats:
- The original tests contain extremely minor alterations due testing/environment issues.
- PHP 5.3 has a weird bug where class aliases aren't being registered properly. Because of this, the classes had
to be extended from their respective replacements. This, unfortunately, prevents
\PhpOption\Some,\PhpOption\Noneand\PhpOption\LazyOptionfrom being able to be extended directly from\PhpOption\Option. If your code implements anything resembling$option instanceof Option, these will fail. You will need to change these to$option instance of \UnicornFail\PhpOption\OptionInterfaceinstead.
Version 2.0.0
- This project plans to remove support for all of
PHP 5,PHP 7.0,PHP 7.1and backward compatibility with phpoption/phpoption.
⛔ Security
To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure with us.
👷♀️ Contributing
Contributions to this library are welcome!
Please see CONTRIBUTING for additional details.
🧪 Testing
Local development (ignore changes to composer.json):
$ composer require-test
$ composer test
With coverage:
$ composer require-test $ composer require-coverage $ composer test-coverage
🚀 Performance Benchmarks
Of course, performance is important. Included in the tests is a performance benchmark which you can run on a machine of your choosing:
$ composer test-group performance
At its core, the overhead incurred by using Option comes down to the time that it takes to
create one object, the Option wrapper. It will also need to perform an additional method
call to retrieve the value from the wrapper. Depending on your use case(s) and desired
functionality, you may encounter varied results.
Average Overhead Per Invocation*
In the table above, these benchmarks rarely are well under a fraction of a microsecond. Many of them measure in nanoseconds; with newer PHP versions decreasing the overhead even more over time.
Unless you plan to call a method hundreds of thousands of times during a request, there is no reason
to stick to the object|null return value; better give your code some options!
*Average based on the comparison of creating a single object vs. the creation of a wrapper and a single method call; iterated over 10000 times and then calculating the difference.
👥 Credits & Acknowledgements
- Mark Carver (twitter) (github)
- Johannes (twitter) (github)
- All Contributors
📄 License
unicorn-fail/php-option is licensed under the Apache 2.0 license. See the LICENSE file for more details.
unicorn-fail/php-option 适用场景与选型建议
unicorn-fail/php-option 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 26 次下载、GitHub Stars 达 2, 最近一次更新时间为 2019 年 08 月 07 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「php」 「language」 「type」 「option」 「typed」 「phpoption」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 unicorn-fail/php-option 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 unicorn-fail/php-option 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 unicorn-fail/php-option 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Texy converts plain text in easy to read Texy syntax into structurally valid (X)HTML. It supports adding of images, links, nested lists, tables and has full support for CSS. Texy supports hyphenation of long words (which reflects language rules), clickable emails and URL (emails are obfuscated again
A bundle providing fields for image upload with jquery upload and image cropping with jcrop for symfony2
Easy to use i18n translation PHP class for multi-language websites
A simple Symfony bundle that adds boolean form field type.
Package for convenient work with Laravel's localization features
Store your language lines in the database, yaml or other sources
统计信息
- 总下载量: 26
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 2
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: Apache-2.0
- 更新时间: 2019-08-07