承接 unicorn-fail/php-option 相关项目开发

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

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

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 TypedOption support.

Latest Version Total Downloads License PHP from Packagist

Build Status Codacy grade Codacy coverage phpcs coding standard

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\LazyOption
    • PhpOption\None => UnicornFail\PhpOption\None
    • PhpOption\Option => UnicornFail\PhpOption\Option
    • PhpOption\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\None and \PhpOption\LazyOption from 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\OptionInterface instead.

Version 2.0.0

  • This project plans to remove support for all of PHP 5, PHP 7.0, PHP 7.1 and 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*

None::create() Some::create()
PHP 5.3 0.000000539s 0.000010369s
PHP 5.4 0.000000427s 0.000007331s
PHP 5.5 0.000000422s 0.000007045s
PHP 5.6 0.000001036s 0.000006680s
PHP 7.0 0.000000185s 0.000002357s
PHP 7.1 0.000000124s 0.000002027s
PHP 7.2 0.000000127s 0.000001841s
PHP 7.3 0.000000111s 0.000001682s

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

📄 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 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

  • 总下载量: 26
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 2
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 2
  • Watchers: 0
  • Forks: 67
  • 开发语言: PHP

其他信息

  • 授权协议: Apache-2.0
  • 更新时间: 2019-08-07