4
4
5
5
[ ![ Build Status]] [ Latest build ]
6
6
[ ![ Test Coverage]] [ Test coverage report ]
7
+ [ ![ Uses Semantic Versioning]] [ SemVer ]
7
8
8
9
## Installation and documentation
9
10
@@ -26,9 +27,9 @@ Enumeration can be used like [C++ enumerated types]. Here is an example,
26
27
representing a set of HTTP request methods:
27
28
28
29
``` php
29
- use Eloquent\Enumeration\Enumeration ;
30
+ use Eloquent\Enumeration\AbstractEnumeration ;
30
31
31
- final class HttpRequestMethod extends Enumeration
32
+ final class HttpRequestMethod extends AbstractEnumeration
32
33
{
33
34
const OPTIONS = 'OPTIONS';
34
35
const GET = 'GET';
@@ -61,7 +62,7 @@ handleHttpRequest(HttpRequestMethod::POST(), 'http://example.org/', 'foo=bar&baz
61
62
```
62
63
63
64
For each member of the enumeration, a single instance of the enumeration class
64
- is instantiated (that is, an instance of * HttpRequestMethod* in the above
65
+ is instantiated (that is, an instance of ` HttpRequestMethod ` in the above
65
66
example). This means that strict comparison (===) can be used to determine
66
67
which member has been passed to a function:
67
68
@@ -91,9 +92,9 @@ following multiton describes all of the planets in our solar system, including
91
92
their masses and radii:
92
93
93
94
``` php
94
- use Eloquent\Enumeration\Multiton ;
95
+ use Eloquent\Enumeration\AbstractMultiton ;
95
96
96
- final class Planet extends Multiton
97
+ final class Planet extends AbstractMultiton
97
98
{
98
99
/**
99
100
* Universal gravitational constant
@@ -122,8 +123,6 @@ final class Planet extends Multiton
122
123
123
124
protected static function initializeMembers()
124
125
{
125
- parent::initializeMembers();
126
-
127
126
new static('MERCURY', 3.302e23, 2.4397e6);
128
127
new static('VENUS', 4.869e24, 6.0518e6);
129
128
new static('EARTH', 5.9742e24, 6.37814e6);
@@ -148,14 +147,7 @@ final class Planet extends Multiton
148
147
$this->radius = $radius;
149
148
}
150
149
151
- /**
152
- * @var float
153
- */
154
150
private $mass;
155
-
156
- /**
157
- * @var float
158
- */
159
151
private $radius;
160
152
}
161
153
```
@@ -176,7 +168,8 @@ foreach (Planet::members() as $planet) {
176
168
}
177
169
```
178
170
179
- If you run the above script you will get something like the following output:
171
+ If the above script is executed, it will produce something like the following
172
+ output:
180
173
181
174
```
182
175
Your weight on MERCURY is 66.107480
@@ -189,6 +182,83 @@ Your weight on URANUS is 158.424919
189
182
Your weight on NEPTUNE is 199.055584
190
183
```
191
184
185
+ ## Enumerations and class inheritance
186
+
187
+ When an enumeration is defined, the intent is usually to define a set of valid
188
+ values that should not change, at least within the lifetime of a program's
189
+ execution.
190
+
191
+ Since PHP has no in-built support for enumerations, this library implements them
192
+ as regular PHP classes. Classes, however, allow for much more extensibility than
193
+ is desirable in a true enumeration.
194
+
195
+ For example, a naive enumeration implementation might allow a developer to
196
+ extend the ` HttpRequestMethod ` class from the examples above (assuming the
197
+ ` final ` keyword is removed):
198
+
199
+ ``` php
200
+ class CustomHttpMethod extends HttpRequestMethod
201
+ {
202
+ const PATCH = 'PATCH';
203
+ }
204
+ ```
205
+
206
+ The problem with this scenario is that all the code written to expect only the
207
+ HTTP methods defined in ` HttpRequestMethod ` is now compromised. Anybody can
208
+ extend ` HttpRequestMethod ` to add custom values, essentially voiding the reason
209
+ for defining ` HttpRequestMethod ` in the first place.
210
+
211
+ This library provides built-in protection from these kinds of circumstances.
212
+ Attempting to define an enumeration that extends another enumeration will result
213
+ in an exception being thrown, unless the 'base' enumeration is abstract.
214
+
215
+ ### Abstract enumerations
216
+
217
+ Assuming that there really is a need to extend ` HttpRequestMethod ` , the way to
218
+ go about it is to define an abstract base class, then extend this class to
219
+ create the desired concrete enumerations:
220
+
221
+ ``` php
222
+ use Eloquent\Enumeration\AbstractEnumeration;
223
+
224
+ abstract class AbstractHttpRequestMethod extends AbstractEnumeration
225
+ {
226
+ const OPTIONS = 'OPTIONS';
227
+ const GET = 'GET';
228
+ const HEAD = 'HEAD';
229
+ const POST = 'POST';
230
+ const PUT = 'PUT';
231
+ const DELETE = 'DELETE';
232
+ const TRACE = 'TRACE';
233
+ const CONNECT = 'CONNECT';
234
+ }
235
+
236
+ final class HttpRequestMethod extends AbstractHttpRequestMethod {}
237
+
238
+ final class CustomHttpMethod extends AbstractHttpRequestMethod
239
+ {
240
+ const PATCH = 'PATCH';
241
+ }
242
+ ```
243
+
244
+ In this way, when a developer uses a type hint for ` HttpRequestMethod ` , there is
245
+ no chance they will ever receive the 'PATCH' method:
246
+
247
+ ``` php
248
+ function handleHttpRequest(HttpRequestMethod $method, $url, $body = null)
249
+ {
250
+ // only handles normal requests...
251
+ }
252
+
253
+ function handleCustomHttpRequest(
254
+ CustomHttpRequestMethod $method,
255
+ $url,
256
+ $body = null
257
+ ) {
258
+ // handles normal requests, and custom requests...
259
+ }
260
+ ```
261
+
192
262
<!-- References -->
193
263
194
264
[ API documentation ] : http://lqnt.co/enumeration/artifacts/documentation/api/
@@ -201,5 +271,7 @@ Your weight on NEPTUNE is 199.055584
201
271
202
272
[ Build Status ] : https://api.travis-ci.org/eloquent/enumeration.png?branch=master
203
273
[ Latest build ] : https://travis-ci.org/eloquent/enumeration
274
+ [ SemVer ] : http://semver.org/
204
275
[ Test coverage report ] : https://coveralls.io/r/eloquent/enumeration
205
276
[ Test Coverage ] : https://coveralls.io/repos/eloquent/enumeration/badge.png?branch=master
277
+ [ Uses Semantic Versioning ] : http://b.repl.ca/v1/semver-yes-brightgreen.png
0 commit comments