Skip to content

Commit 7367f9e

Browse files
committed
WIP state machine pattern for generators
1 parent bee66d0 commit 7367f9e

14 files changed

+122
-108
lines changed

src/Container/Container.php

+18-23
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,20 @@
1414
final class Container implements ContainerInterface
1515
{
1616
/**
17-
* @var array<string, callable|object|string>
17+
* @var array<string, callable(): Extension|Extension|class-string<Extension>>
1818
*/
19-
private $definitions;
19+
private array $definitions;
2020

21-
private $services = [];
21+
/**
22+
* @var array<string, mixed>
23+
*/
24+
private array $services = [];
2225

2326
/**
2427
* Create a container object with a set of definitions. The array value MUST
2528
* produce an object that implements Extension.
2629
*
27-
* @param array<string, callable|object|string> $definitions
30+
* @param array<string, callable(): Extension|Extension|class-string<Extension>> $definitions
2831
*/
2932
public function __construct(array $definitions)
3033
{
@@ -41,15 +44,8 @@ public function __construct(array $definitions)
4144
* @throws ContainerException
4245
* @throws NotInContainerException
4346
*/
44-
public function get($id): Extension
47+
public function get(string $id): Extension
4548
{
46-
if (!is_string($id)) {
47-
throw new \InvalidArgumentException(sprintf(
48-
'First argument of %s::get() must be string',
49-
self::class
50-
));
51-
}
52-
5349
if (array_key_exists($id, $this->services)) {
5450
return $this->services[$id];
5551
}
@@ -79,9 +75,13 @@ public function get($id): Extension
7975
/**
8076
* Get the service from a definition.
8177
*
82-
* @param callable|object|string $definition
78+
* @template T of \Faker\Core\Extension\Extension
79+
*
80+
* @param callable(): T|T|class-string<T> $definition
81+
*
82+
* @return T
8383
*/
84-
private function getService($id, $definition)
84+
private function getService(string $id, callable|object|string $definition): object
8585
{
8686
if (is_callable($definition)) {
8787
try {
@@ -121,22 +121,17 @@ private function getService($id, $definition)
121121
*
122122
* @param string $id
123123
*
124-
* @throws \InvalidArgumentException
124+
* @return bool
125125
*/
126-
public function has($id): bool
126+
public function has(string $id): bool
127127
{
128-
if (!is_string($id)) {
129-
throw new \InvalidArgumentException(sprintf(
130-
'First argument of %s::get() must be string',
131-
self::class
132-
));
133-
}
134-
135128
return array_key_exists($id, $this->definitions);
136129
}
137130

138131
/**
139132
* Get the bindings between Extension interfaces and implementations.
133+
*
134+
* @return array<string, callable(): Extension|Extension|class-string<Extension>>
140135
*/
141136
public function getDefinitions(): array
142137
{

src/Container/ContainerBuilder.php

+7-13
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
namespace Faker\Core\Container;
66

7+
use Faker\Core\Extension\Extension;
78
use Faker\Core\Implementation;
89
use Faker\Core\Extension\BarcodeExtension;
910
use Faker\Core\Extension\BloodExtension;
1011
use Faker\Core\Extension\ColorExtension;
1112
use Faker\Core\Extension\DateTimeExtension;
1213
use Faker\Core\Extension\FileExtension;
1314
use Faker\Core\Extension\NumberExtension;
14-
use Faker\Core\Extension\UuidExtension;
1515
use Faker\Core\Extension\VersionExtension;
1616

1717
/**
@@ -20,24 +20,17 @@
2020
final class ContainerBuilder
2121
{
2222
/**
23-
* @var array<string, callable|object|string>
23+
* @var array<string, callable|object|class-string>
2424
*/
25-
private $definitions = [];
25+
private array $definitions = [];
2626

2727
/**
28-
* @param callable|object|string $value
28+
* @param callable|object|class-string $value
2929
*
3030
* @throws \InvalidArgumentException
3131
*/
32-
public function add($value, string $name = null): self
32+
public function add(callable|object|string $value, string $name = null): self
3333
{
34-
if (!is_string($value) && !is_callable($value) && !is_object($value)) {
35-
throw new \InvalidArgumentException(sprintf(
36-
'First argument to "%s::add()" must be a string, callable or object.',
37-
self::class
38-
));
39-
}
40-
4134
if ($name === null) {
4235
if (is_string($value)) {
4336
$name = $value;
@@ -64,6 +57,8 @@ public function build(): ContainerInterface
6457
/**
6558
* Get an array with extension that represent the default English
6659
* functionality.
60+
*
61+
* @return array<class-string<Extension>, class-string<Extension>>
6762
*/
6863
public static function defaultExtensions(): array
6964
{
@@ -75,7 +70,6 @@ public static function defaultExtensions(): array
7570
FileExtension::class => Implementation\File::class,
7671
NumberExtension::class => Implementation\Number::class,
7772
VersionExtension::class => Implementation\Version::class,
78-
UuidExtension::class => Implementation\Uuid::class,
7973
];
8074
}
8175

src/Container/ContainerInterface.php

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ interface ContainerInterface extends BaseContainerInterface
88
{
99
/**
1010
* Get the bindings between Extension interfaces and implementations.
11+
*
12+
* @return array<class-string, class-string>
1113
*/
1214
public function getDefinitions(): array;
1315
}

src/Generator.php src/DefaultGenerator.php

+25-11
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
use Faker\Core\Extension\FileExtension;
1414
use Faker\Core\Extension\GeneratorAwareExtension;
1515
use Faker\Core\Extension\NumberExtension;
16-
use Faker\Core\Extension\UuidExtension;
1716
use Faker\Core\Extension\VersionExtension;
17+
use Faker\Core\Generator\ChanceGenerator;
18+
use Faker\Core\Generator\UniqueGenerator;
19+
use Faker\Core\Generator\ValidGenerator;
1820

1921
/**
2022
* @mixin BarcodeExtension
@@ -24,9 +26,8 @@
2426
* @mixin FileExtension
2527
* @mixin NumberExtension
2628
* @mixin VersionExtension
27-
* @mixin UuidExtension
2829
*/
29-
class Generator
30+
class DefaultGenerator
3031
{
3132
protected array $formatters = [];
3233

@@ -38,13 +39,12 @@ public function __construct(ContainerInterface $container = null)
3839
}
3940

4041
/**
41-
* @template T of Extension\Extension
42+
* @template T of \Faker\Core\Extension\Extension
4243
*
4344
* @param class-string<T> $id
4445
*
4546
* @return T
4647
* @throws ExtensionNotFound
47-
*
4848
*/
4949
public function ext(string $id): Extension
5050
{
@@ -74,17 +74,17 @@ public function ext(string $id): Extension
7474
* </code>
7575
*
7676
* @param bool $reset If set to true, resets the list of existing values
77-
* @param int $maxRetries Maximum number of retries to find a unique value,
77+
* @param int $retries Maximum number of retries to find a unique value,
7878
* After which an OverflowException is thrown.
7979
*
8080
* @return self A proxy class returning only non-existing values
8181
* @throws \OverflowException When no unique value can be found by iterating $maxRetries times
8282
*
8383
*/
84-
public function unique($reset = false, $maxRetries = 10000)
84+
public function unique(bool $reset = false, int $retries = 10000)
8585
{
8686
if ($reset || $this->uniqueGenerator === null) {
87-
$this->uniqueGenerator = new UniqueGenerator($this, $maxRetries);
87+
$this->uniqueGenerator = new UniqueGenerator($this, $retries);
8888
}
8989

9090
return $this->uniqueGenerator;
@@ -117,7 +117,7 @@ public function optional(float $weight = 0.5, $default = null)
117117
* $values []= $faker->valid($evenValidator)->randomDigit;
118118
* }
119119
* print_r($values); // [0, 4, 8, 4, 2, 6, 0, 8, 8, 6]
120-
* </code>
120+
* </code>a
121121
*
122122
* @param ?\Closure $validator A function returning true for valid values
123123
* @param int $maxRetries Maximum number of retries to find a valid value,
@@ -151,7 +151,7 @@ public function format($format, $arguments = [])
151151
*
152152
* @return callable
153153
*/
154-
public function getFormatter($format): callable
154+
public function getFormatter(string $format): callable
155155
{
156156
if (isset($this->formatters[$format])) {
157157
return $this->formatters[$format];
@@ -180,7 +180,7 @@ public function getFormatter($format): callable
180180
*
181181
* @return string
182182
*/
183-
public function parse($string)
183+
public function parse(string $string): string
184184
{
185185
$callback = function ($matches) {
186186
return $this->format($matches[1]);
@@ -189,4 +189,18 @@ public function parse($string)
189189
return preg_replace_callback('/{{\s?(\w+|[\w\\\]+->\w+?)\s?}}/u', $callback, $string);
190190
}
191191

192+
public function __call(string $name, array $arguments)
193+
{
194+
return $this->format($name, $arguments);
195+
}
196+
197+
public function __destruct()
198+
{
199+
$this->seed();
200+
}
201+
202+
public function __wakeup(): void
203+
{
204+
$this->formatters = [];
205+
}
192206
}

src/Extension/GeneratorAwareExtension.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Faker\Core\Extension;
66

7-
use Faker\Core\Generator;
7+
use Faker\Core\DefaultGenerator;
88

99
/**
1010
* @experimental This interface is experimental and does not fall under our BC promise
@@ -14,7 +14,8 @@ interface GeneratorAwareExtension extends Extension
1414
/**
1515
* This method MUST be implemented in such a way as to retain the
1616
* immutability of the extension, and MUST return an instance that has the
17-
* new Generator.
17+
* new DefaultGenerator.
1818
*/
19-
public function withGenerator(Generator $generator): Extension;
19+
// TODO: make generator more generic, with different generation strategies
20+
public function withGenerator(DefaultGenerator $generator): Extension;
2021
}

src/Extension/GeneratorAwareExtensionTrait.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@
55
namespace Faker\Core\Extension;
66

77

8-
use Faker\Core\Generator;
8+
use Faker\Core\DefaultGenerator;
99

1010
/**
1111
* A helper trait to be used with GeneratorAwareExtension.
1212
*/
1313
trait GeneratorAwareExtensionTrait
1414
{
1515
/**
16-
* @var Generator|null
16+
* @var DefaultGenerator
1717
*/
1818
private $generator;
1919

2020
/**
2121
* @return static
2222
*/
23-
public function withGenerator(Generator $generator): Extension
23+
public function withGenerator(DefaultGenerator $generator): Extension
2424
{
2525
$instance = clone $this;
2626

src/Extension/Helper.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ final class Helper
1111
{
1212
/**
1313
* Returns a random element from a passed array.
14+
*
15+
* @param array<int|string, mixed> $array
1416
*/
15-
public static function randomElement(array $array)
17+
public static function randomElement(array $array): mixed
1618
{
1719
if ($array === []) {
1820
return null;

src/ChanceGenerator.php src/Generator/ChanceGenerator.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<?php
22

3-
namespace Faker\Core;
3+
namespace Faker\Core\Generator;
44

5+
use Faker\Core\DefaultGenerator;
56
use Faker\Core\Extension\Extension;
67

78
/**
89
* This generator returns a default value for all called properties
9-
* and methods. It works with Faker\Generator::optional().
10+
* and methods. It works with Faker\DefaultGenerator::optional().
1011
*
11-
* @mixin Generator
12+
* @mixin DefaultGenerator
1213
*/
1314
class ChanceGenerator
1415
{
@@ -17,7 +18,7 @@ class ChanceGenerator
1718
protected $default;
1819

1920
/**
20-
* @param Extension|Generator $generator
21+
* @param Extension|DefaultGenerator $generator
2122
*/
2223
public function __construct($generator, float $weight, $default = null)
2324
{

0 commit comments

Comments
 (0)