UniqueGenerator.php 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. <?php
  2. namespace Faker;
  3. use Faker\Extension\Extension;
  4. /**
  5. * Proxy for other generators that returns only unique values.
  6. *
  7. * Instantiated through @see Generator::unique().
  8. *
  9. * @mixin Generator
  10. */
  11. class UniqueGenerator
  12. {
  13. protected $generator;
  14. protected $maxRetries;
  15. /**
  16. * Maps from method names to a map with serialized result keys.
  17. *
  18. * @example [
  19. * 'phone' => ['0123' => null],
  20. * 'city' => ['London' => null, 'Tokyo' => null],
  21. * ]
  22. *
  23. * @var array<string, array<string, null>>
  24. */
  25. protected $uniques = [];
  26. /**
  27. * @param Extension|Generator $generator
  28. * @param int $maxRetries
  29. * @param array<string, array<string, null>> $uniques
  30. */
  31. public function __construct($generator, $maxRetries = 10000, &$uniques = [])
  32. {
  33. $this->generator = $generator;
  34. $this->maxRetries = $maxRetries;
  35. $this->uniques = &$uniques;
  36. }
  37. public function ext(string $id)
  38. {
  39. return new self($this->generator->ext($id), $this->maxRetries, $this->uniques);
  40. }
  41. /**
  42. * Catch and proxy all generator calls but return only unique values
  43. *
  44. * @param string $attribute
  45. *
  46. * @deprecated Use a method instead.
  47. */
  48. public function __get($attribute)
  49. {
  50. trigger_deprecation('fakerphp/faker', '1.14', 'Accessing property "%s" is deprecated, use "%s()" instead.', $attribute, $attribute);
  51. return $this->__call($attribute, []);
  52. }
  53. /**
  54. * Catch and proxy all generator calls with arguments but return only unique values
  55. *
  56. * @param string $name
  57. * @param array $arguments
  58. */
  59. public function __call($name, $arguments)
  60. {
  61. if (!isset($this->uniques[$name])) {
  62. $this->uniques[$name] = [];
  63. }
  64. $i = 0;
  65. do {
  66. $res = call_user_func_array([$this->generator, $name], $arguments);
  67. ++$i;
  68. if ($i > $this->maxRetries) {
  69. throw new \OverflowException(sprintf('Maximum retries of %d reached without finding a unique value', $this->maxRetries));
  70. }
  71. } while (array_key_exists(serialize($res), $this->uniques[$name]));
  72. $this->uniques[$name][serialize($res)] = null;
  73. return $res;
  74. }
  75. }