File: README.md

package info (click to toggle)
php-phpoption 1.7.5-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, sid
  • size: 232 kB
  • sloc: php: 1,087; makefile: 23; xml: 12
file content (203 lines) | stat: -rw-r--r-- 6,798 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# PHP Option Type

This package implements the Option type for PHP!

![Banner](https://user-images.githubusercontent.com/2829600/71564011-3077bf00-2a91-11ea-9083-905702cc262b.png)

<p align="center">
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg?style=flat-square" alt="Software License"></img></a>
<a href="https://packagist.org/packages/phpoption/phpoption"><img src="https://img.shields.io/packagist/dt/phpoption/phpoption.svg?style=flat-square" alt="Total Downloads"></img></a>
<a href="https://github.com/schmittjoh/php-option/releases"><img src="https://img.shields.io/github/release/schmittjoh/php-option.svg?style=flat-square" alt="Latest Version"></img></a>
</p>


## Motivation

The Option type is intended for cases where you sometimes might return a value
(typically an object), and sometimes you might return a base value (typically
null) depending on arguments, or other runtime factors.

Often times, you forget to handle the case where a base value should be
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 base 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, the Option type forces a developer to consciously think about both
cases (returning a value, or returning a base value). That in itself will
already make your code more robust. On the other hand, the Option type also
allows the API developer to provide more concise API methods, and empowers the
API user in how he consumes these methods.


## Installation

Installation is super-easy via [Composer](https://getcomposer.org/):

```bash
$ composer require phpoption/phpoption
```

or add it by hand to your `composer.json` file.


## Usage

### Using the Option Type in your API

```php
class MyRepository
{
    public function findSomeEntity($criteria)
    {
        if (null !== $entity = $this->em->find(...)) {
            return new \PhpOption\Some($entity);
        }

        // We use a singleton, for the None case.
        return \PhpOption\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:

```php
class MyRepository
{
    public function findSomeEntity($criteria)
    {
        return \PhpOption\Option::fromValue($this->em->find(...));

        // or, if you want to change the none value to false for example:
        return \PhpOption\Option::fromValue($this->em->find(...), false);
    }
}
```

### Case 1: You always Require an Entity in Calling Code

```php
$entity = $repo->findSomeEntity(...)->get(); // returns entity, or throws exception
```

### Case 2: Fallback to Default Value If Not Available

```php
$entity = $repo->findSomeEntity(...)->getOrElse(new Entity());

// Or, if you want to lazily create the entity.
$entity = $repo->findSomeEntity(...)->getOrCall(function() {
    return new Entity();
});
```

## More Examples

### No More Boiler Plate Code

```php
// Before
if (null === $entity = $this->findSomeEntity()) {
    throw new NotFoundException();
}
echo $entity->name;

// After
echo $this->findSomeEntity()->get()->name;
```

### No More Control Flow Exceptions

```php
// Before
try {
    $entity = $this->findSomeEntity();
} catch (NotFoundException $ex) {
    $entity = new Entity();
}

// After
$entity = $this->findSomeEntity()->getOrElse(new Entity());
```

### More Concise Null Handling

```php
// Before
$entity = $this->findSomeEntity();
if (null === $entity) {
    return new Entity();
}

return $entity;

// After
return $this->findSomeEntity()->getOrElse(new Entity());
```

### Trying Multiple Alternative Options

If you'd like to try multiple alternatives, the ``orElse`` method allows you to
do this very elegantly:

```php
return $this->findSomeEntity()
            ->orElse($this->findSomeOtherEntity())
            ->orElse($this->createEntity());
```
The first option which is non-empty will be returned. This is especially useful 
with lazy-evaluated options, see below.

### Lazy-Evaluated Options

The above example has the flaw that we would need to evaluate all options when
the method is called which creates unnecessary overhead if the first option is 
already non-empty.

Fortunately, we can easily solve this by using the ``LazyOption`` class:

```php
return $this->findSomeEntity()
            ->orElse(new LazyOption(array($this, 'findSomeOtherEntity')))
            ->orElse(new LazyOption(array($this, 'createEntity')));
```

This way, only the options that are necessary will actually be evaluated.

## Performance Considerations

Of course, performance is important. Attached is a performance benchmark which
you can run on a machine of your choosing.

The overhead incurred by the Option type comes down to the time that it takes to
create one object, our wrapper. Also, we need to perform one additional method call
to retrieve the value from the wrapper.

* Overhead: Creation of 1 Object, and 1 Method Call
* Average Overhead per Invocation (some case/value returned): 0.000000761s (that is 761 nano seconds)
* Average Overhead per Invocation (none case/null returned): 0.000000368s (that is 368 nano seconds)

The benchmark was run under Ubuntu precise with PHP 5.4.6. As you can see the
overhead is surprisingly low, almost negligible.

So in conclusion, unless you plan to call a method thousands of times during a
request, there is no reason to stick to the ``object|null`` return value; better give
your code some options!

## Security

If you discover a security vulnerability within this package, please send an email to one of the security contacts. All security vulnerabilities will be promptly addressed. You may view our full security policy [here](https://github.com/schmittjoh/php-option/security/policy).

## License

PHP Option Type is licensed under [Apache License 2.0](LICENSE).

## For Enterprise

Available as part of the Tidelift Subscription

The maintainers of `phpoption/phpoption` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-phpoption-phpoption?utm_source=packagist-phpoption-phpoption&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)