diff options
Diffstat (limited to 'vendor/doctrine/instantiator')
13 files changed, 681 insertions, 0 deletions
diff --git a/vendor/doctrine/instantiator/.doctrine-project.json b/vendor/doctrine/instantiator/.doctrine-project.json new file mode 100644 index 0000000..24ae36e --- /dev/null +++ b/vendor/doctrine/instantiator/.doctrine-project.json | |||
@@ -0,0 +1,47 @@ | |||
1 | { | ||
2 | "active": true, | ||
3 | "name": "Instantiator", | ||
4 | "slug": "instantiator", | ||
5 | "docsSlug": "doctrine-instantiator", | ||
6 | "codePath": "/src", | ||
7 | "versions": [ | ||
8 | { | ||
9 | "name": "1.5", | ||
10 | "branchName": "1.5.x", | ||
11 | "slug": "latest", | ||
12 | "upcoming": true | ||
13 | }, | ||
14 | { | ||
15 | "name": "1.4", | ||
16 | "branchName": "1.4.x", | ||
17 | "slug": "1.4", | ||
18 | "aliases": [ | ||
19 | "current", | ||
20 | "stable" | ||
21 | ], | ||
22 | "maintained": true, | ||
23 | "current": true | ||
24 | }, | ||
25 | { | ||
26 | "name": "1.3", | ||
27 | "branchName": "1.3.x", | ||
28 | "slug": "1.3", | ||
29 | "maintained": false | ||
30 | }, | ||
31 | { | ||
32 | "name": "1.2", | ||
33 | "branchName": "1.2.x", | ||
34 | "slug": "1.2" | ||
35 | }, | ||
36 | { | ||
37 | "name": "1.1", | ||
38 | "branchName": "1.1.x", | ||
39 | "slug": "1.1" | ||
40 | }, | ||
41 | { | ||
42 | "name": "1.0", | ||
43 | "branchName": "1.0.x", | ||
44 | "slug": "1.0" | ||
45 | } | ||
46 | ] | ||
47 | } | ||
diff --git a/vendor/doctrine/instantiator/CONTRIBUTING.md b/vendor/doctrine/instantiator/CONTRIBUTING.md new file mode 100644 index 0000000..c1a2c42 --- /dev/null +++ b/vendor/doctrine/instantiator/CONTRIBUTING.md | |||
@@ -0,0 +1,35 @@ | |||
1 | # Contributing | ||
2 | |||
3 | * Follow the [Doctrine Coding Standard](https://github.com/doctrine/coding-standard) | ||
4 | * The project will follow strict [object calisthenics](http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php) | ||
5 | * Any contribution must provide tests for additional introduced conditions | ||
6 | * Any un-confirmed issue needs a failing test case before being accepted | ||
7 | * Pull requests must be sent from a new hotfix/feature branch, not from `master`. | ||
8 | |||
9 | ## Installation | ||
10 | |||
11 | To install the project and run the tests, you need to clone it first: | ||
12 | |||
13 | ```sh | ||
14 | $ git clone git://github.com/doctrine/instantiator.git | ||
15 | ``` | ||
16 | |||
17 | You will then need to run a composer installation: | ||
18 | |||
19 | ```sh | ||
20 | $ cd Instantiator | ||
21 | $ curl -s https://getcomposer.org/installer | php | ||
22 | $ php composer.phar update | ||
23 | ``` | ||
24 | |||
25 | ## Testing | ||
26 | |||
27 | The PHPUnit version to be used is the one installed as a dev- dependency via composer: | ||
28 | |||
29 | ```sh | ||
30 | $ ./vendor/bin/phpunit | ||
31 | ``` | ||
32 | |||
33 | Accepted coverage for new contributions is 80%. Any contribution not satisfying this requirement | ||
34 | won't be merged. | ||
35 | |||
diff --git a/vendor/doctrine/instantiator/LICENSE b/vendor/doctrine/instantiator/LICENSE new file mode 100644 index 0000000..4d983d1 --- /dev/null +++ b/vendor/doctrine/instantiator/LICENSE | |||
@@ -0,0 +1,19 @@ | |||
1 | Copyright (c) 2014 Doctrine Project | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
4 | this software and associated documentation files (the "Software"), to deal in | ||
5 | the Software without restriction, including without limitation the rights to | ||
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
7 | of the Software, and to permit persons to whom the Software is furnished to do | ||
8 | so, subject to the following conditions: | ||
9 | |||
10 | The above copyright notice and this permission notice shall be included in all | ||
11 | copies or substantial portions of the Software. | ||
12 | |||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
19 | SOFTWARE. | ||
diff --git a/vendor/doctrine/instantiator/README.md b/vendor/doctrine/instantiator/README.md new file mode 100644 index 0000000..1fa9567 --- /dev/null +++ b/vendor/doctrine/instantiator/README.md | |||
@@ -0,0 +1,38 @@ | |||
1 | # Instantiator | ||
2 | |||
3 | This library provides a way of avoiding usage of constructors when instantiating PHP classes. | ||
4 | |||
5 | [](https://travis-ci.org/doctrine/instantiator) | ||
6 | [](https://codecov.io/gh/doctrine/instantiator/branch/master) | ||
7 | [](https://www.versioneye.com/package/php--doctrine--instantiator) | ||
8 | |||
9 | [](https://packagist.org/packages/doctrine/instantiator) | ||
10 | [](https://packagist.org/packages/doctrine/instantiator) | ||
11 | |||
12 | ## Installation | ||
13 | |||
14 | The suggested installation method is via [composer](https://getcomposer.org/): | ||
15 | |||
16 | ```sh | ||
17 | composer require doctrine/instantiator | ||
18 | ``` | ||
19 | |||
20 | ## Usage | ||
21 | |||
22 | The instantiator is able to create new instances of any class without using the constructor or any API of the class | ||
23 | itself: | ||
24 | |||
25 | ```php | ||
26 | $instantiator = new \Doctrine\Instantiator\Instantiator(); | ||
27 | |||
28 | $instance = $instantiator->instantiate(\My\ClassName\Here::class); | ||
29 | ``` | ||
30 | |||
31 | ## Contributing | ||
32 | |||
33 | Please read the [CONTRIBUTING.md](CONTRIBUTING.md) contents if you wish to help out! | ||
34 | |||
35 | ## Credits | ||
36 | |||
37 | This library was migrated from [ocramius/instantiator](https://github.com/Ocramius/Instantiator), which | ||
38 | has been donated to the doctrine organization, and which is now deprecated in favour of this package. | ||
diff --git a/vendor/doctrine/instantiator/composer.json b/vendor/doctrine/instantiator/composer.json new file mode 100644 index 0000000..179145e --- /dev/null +++ b/vendor/doctrine/instantiator/composer.json | |||
@@ -0,0 +1,48 @@ | |||
1 | { | ||
2 | "name": "doctrine/instantiator", | ||
3 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", | ||
4 | "type": "library", | ||
5 | "license": "MIT", | ||
6 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", | ||
7 | "keywords": [ | ||
8 | "instantiate", | ||
9 | "constructor" | ||
10 | ], | ||
11 | "authors": [ | ||
12 | { | ||
13 | "name": "Marco Pivetta", | ||
14 | "email": "ocramius@gmail.com", | ||
15 | "homepage": "https://ocramius.github.io/" | ||
16 | } | ||
17 | ], | ||
18 | "require": { | ||
19 | "php": "^8.1" | ||
20 | }, | ||
21 | "require-dev": { | ||
22 | "ext-phar": "*", | ||
23 | "ext-pdo": "*", | ||
24 | "doctrine/coding-standard": "^11", | ||
25 | "phpbench/phpbench": "^1.2", | ||
26 | "phpstan/phpstan": "^1.9.4", | ||
27 | "phpstan/phpstan-phpunit": "^1.3", | ||
28 | "phpunit/phpunit": "^9.5.27", | ||
29 | "vimeo/psalm": "^5.4" | ||
30 | }, | ||
31 | "autoload": { | ||
32 | "psr-4": { | ||
33 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" | ||
34 | } | ||
35 | }, | ||
36 | "autoload-dev": { | ||
37 | "psr-0": { | ||
38 | "DoctrineTest\\InstantiatorPerformance\\": "tests", | ||
39 | "DoctrineTest\\InstantiatorTest\\": "tests", | ||
40 | "DoctrineTest\\InstantiatorTestAsset\\": "tests" | ||
41 | } | ||
42 | }, | ||
43 | "config": { | ||
44 | "allow-plugins": { | ||
45 | "dealerdirect/phpcodesniffer-composer-installer": true | ||
46 | } | ||
47 | } | ||
48 | } | ||
diff --git a/vendor/doctrine/instantiator/docs/en/index.rst b/vendor/doctrine/instantiator/docs/en/index.rst new file mode 100644 index 0000000..0c85da0 --- /dev/null +++ b/vendor/doctrine/instantiator/docs/en/index.rst | |||
@@ -0,0 +1,68 @@ | |||
1 | Introduction | ||
2 | ============ | ||
3 | |||
4 | This library provides a way of avoiding usage of constructors when instantiating PHP classes. | ||
5 | |||
6 | Installation | ||
7 | ============ | ||
8 | |||
9 | The suggested installation method is via `composer`_: | ||
10 | |||
11 | .. code-block:: console | ||
12 | |||
13 | $ composer require doctrine/instantiator | ||
14 | |||
15 | Usage | ||
16 | ===== | ||
17 | |||
18 | The instantiator is able to create new instances of any class without | ||
19 | using the constructor or any API of the class itself: | ||
20 | |||
21 | .. code-block:: php | ||
22 | |||
23 | <?php | ||
24 | |||
25 | use Doctrine\Instantiator\Instantiator; | ||
26 | use App\Entities\User; | ||
27 | |||
28 | $instantiator = new Instantiator(); | ||
29 | |||
30 | $user = $instantiator->instantiate(User::class); | ||
31 | |||
32 | Contributing | ||
33 | ============ | ||
34 | |||
35 | - Follow the `Doctrine Coding Standard`_ | ||
36 | - The project will follow strict `object calisthenics`_ | ||
37 | - Any contribution must provide tests for additional introduced | ||
38 | conditions | ||
39 | - Any un-confirmed issue needs a failing test case before being | ||
40 | accepted | ||
41 | - Pull requests must be sent from a new hotfix/feature branch, not from | ||
42 | ``master``. | ||
43 | |||
44 | Testing | ||
45 | ======= | ||
46 | |||
47 | The PHPUnit version to be used is the one installed as a dev- dependency | ||
48 | via composer: | ||
49 | |||
50 | .. code-block:: console | ||
51 | |||
52 | $ ./vendor/bin/phpunit | ||
53 | |||
54 | Accepted coverage for new contributions is 80%. Any contribution not | ||
55 | satisfying this requirement won’t be merged. | ||
56 | |||
57 | Credits | ||
58 | ======= | ||
59 | |||
60 | This library was migrated from `ocramius/instantiator`_, which has been | ||
61 | donated to the doctrine organization, and which is now deprecated in | ||
62 | favour of this package. | ||
63 | |||
64 | .. _composer: https://getcomposer.org/ | ||
65 | .. _CONTRIBUTING.md: CONTRIBUTING.md | ||
66 | .. _ocramius/instantiator: https://github.com/Ocramius/Instantiator | ||
67 | .. _Doctrine Coding Standard: https://github.com/doctrine/coding-standard | ||
68 | .. _object calisthenics: http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php | ||
diff --git a/vendor/doctrine/instantiator/docs/en/sidebar.rst b/vendor/doctrine/instantiator/docs/en/sidebar.rst new file mode 100644 index 0000000..0c36479 --- /dev/null +++ b/vendor/doctrine/instantiator/docs/en/sidebar.rst | |||
@@ -0,0 +1,4 @@ | |||
1 | .. toctree:: | ||
2 | :depth: 3 | ||
3 | |||
4 | index | ||
diff --git a/vendor/doctrine/instantiator/psalm.xml b/vendor/doctrine/instantiator/psalm.xml new file mode 100644 index 0000000..e9b622b --- /dev/null +++ b/vendor/doctrine/instantiator/psalm.xml | |||
@@ -0,0 +1,16 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <psalm | ||
3 | errorLevel="7" | ||
4 | phpVersion="8.2" | ||
5 | resolveFromConfigFile="true" | ||
6 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
7 | xmlns="https://getpsalm.org/schema/config" | ||
8 | xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" | ||
9 | > | ||
10 | <projectFiles> | ||
11 | <directory name="src" /> | ||
12 | <ignoreFiles> | ||
13 | <directory name="vendor" /> | ||
14 | </ignoreFiles> | ||
15 | </projectFiles> | ||
16 | </psalm> | ||
diff --git a/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.php b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.php new file mode 100644 index 0000000..1e59192 --- /dev/null +++ b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.php | |||
@@ -0,0 +1,14 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\Instantiator\Exception; | ||
6 | |||
7 | use Throwable; | ||
8 | |||
9 | /** | ||
10 | * Base exception marker interface for the instantiator component | ||
11 | */ | ||
12 | interface ExceptionInterface extends Throwable | ||
13 | { | ||
14 | } | ||
diff --git a/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..5b91a00 --- /dev/null +++ b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php | |||
@@ -0,0 +1,52 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\Instantiator\Exception; | ||
6 | |||
7 | use InvalidArgumentException as BaseInvalidArgumentException; | ||
8 | use ReflectionClass; | ||
9 | |||
10 | use function interface_exists; | ||
11 | use function sprintf; | ||
12 | use function trait_exists; | ||
13 | |||
14 | /** | ||
15 | * Exception for invalid arguments provided to the instantiator | ||
16 | */ | ||
17 | class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface | ||
18 | { | ||
19 | public static function fromNonExistingClass(string $className): self | ||
20 | { | ||
21 | if (interface_exists($className)) { | ||
22 | return new self(sprintf('The provided type "%s" is an interface, and cannot be instantiated', $className)); | ||
23 | } | ||
24 | |||
25 | if (trait_exists($className)) { | ||
26 | return new self(sprintf('The provided type "%s" is a trait, and cannot be instantiated', $className)); | ||
27 | } | ||
28 | |||
29 | return new self(sprintf('The provided class "%s" does not exist', $className)); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * @phpstan-param ReflectionClass<T> $reflectionClass | ||
34 | * | ||
35 | * @template T of object | ||
36 | */ | ||
37 | public static function fromAbstractClass(ReflectionClass $reflectionClass): self | ||
38 | { | ||
39 | return new self(sprintf( | ||
40 | 'The provided class "%s" is abstract, and cannot be instantiated', | ||
41 | $reflectionClass->getName(), | ||
42 | )); | ||
43 | } | ||
44 | |||
45 | public static function fromEnum(string $className): self | ||
46 | { | ||
47 | return new self(sprintf( | ||
48 | 'The provided class "%s" is an enum, and cannot be instantiated', | ||
49 | $className, | ||
50 | )); | ||
51 | } | ||
52 | } | ||
diff --git a/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php new file mode 100644 index 0000000..4f70ded --- /dev/null +++ b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php | |||
@@ -0,0 +1,61 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\Instantiator\Exception; | ||
6 | |||
7 | use Exception; | ||
8 | use ReflectionClass; | ||
9 | use UnexpectedValueException as BaseUnexpectedValueException; | ||
10 | |||
11 | use function sprintf; | ||
12 | |||
13 | /** | ||
14 | * Exception for given parameters causing invalid/unexpected state on instantiation | ||
15 | */ | ||
16 | class UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface | ||
17 | { | ||
18 | /** | ||
19 | * @phpstan-param ReflectionClass<T> $reflectionClass | ||
20 | * | ||
21 | * @template T of object | ||
22 | */ | ||
23 | public static function fromSerializationTriggeredException( | ||
24 | ReflectionClass $reflectionClass, | ||
25 | Exception $exception, | ||
26 | ): self { | ||
27 | return new self( | ||
28 | sprintf( | ||
29 | 'An exception was raised while trying to instantiate an instance of "%s" via un-serialization', | ||
30 | $reflectionClass->getName(), | ||
31 | ), | ||
32 | 0, | ||
33 | $exception, | ||
34 | ); | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | * @phpstan-param ReflectionClass<T> $reflectionClass | ||
39 | * | ||
40 | * @template T of object | ||
41 | */ | ||
42 | public static function fromUncleanUnSerialization( | ||
43 | ReflectionClass $reflectionClass, | ||
44 | string $errorString, | ||
45 | int $errorCode, | ||
46 | string $errorFile, | ||
47 | int $errorLine, | ||
48 | ): self { | ||
49 | return new self( | ||
50 | sprintf( | ||
51 | 'Could not produce an instance of "%s" via un-serialization, since an error was triggered ' | ||
52 | . 'in file "%s" at line "%d"', | ||
53 | $reflectionClass->getName(), | ||
54 | $errorFile, | ||
55 | $errorLine, | ||
56 | ), | ||
57 | 0, | ||
58 | new Exception($errorString, $errorCode), | ||
59 | ); | ||
60 | } | ||
61 | } | ||
diff --git a/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php new file mode 100644 index 0000000..f803f89 --- /dev/null +++ b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php | |||
@@ -0,0 +1,255 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\Instantiator; | ||
6 | |||
7 | use ArrayIterator; | ||
8 | use Doctrine\Instantiator\Exception\ExceptionInterface; | ||
9 | use Doctrine\Instantiator\Exception\InvalidArgumentException; | ||
10 | use Doctrine\Instantiator\Exception\UnexpectedValueException; | ||
11 | use Exception; | ||
12 | use ReflectionClass; | ||
13 | use ReflectionException; | ||
14 | use Serializable; | ||
15 | |||
16 | use function class_exists; | ||
17 | use function enum_exists; | ||
18 | use function is_subclass_of; | ||
19 | use function restore_error_handler; | ||
20 | use function set_error_handler; | ||
21 | use function sprintf; | ||
22 | use function strlen; | ||
23 | use function unserialize; | ||
24 | |||
25 | final class Instantiator implements InstantiatorInterface | ||
26 | { | ||
27 | /** | ||
28 | * Markers used internally by PHP to define whether {@see \unserialize} should invoke | ||
29 | * the method {@see \Serializable::unserialize()} when dealing with classes implementing | ||
30 | * the {@see \Serializable} interface. | ||
31 | * | ||
32 | * @deprecated This constant will be private in 2.0 | ||
33 | */ | ||
34 | private const SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C'; | ||
35 | private const SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O'; | ||
36 | |||
37 | /** | ||
38 | * Used to instantiate specific classes, indexed by class name. | ||
39 | * | ||
40 | * @var callable[] | ||
41 | */ | ||
42 | private static array $cachedInstantiators = []; | ||
43 | |||
44 | /** | ||
45 | * Array of objects that can directly be cloned, indexed by class name. | ||
46 | * | ||
47 | * @var object[] | ||
48 | */ | ||
49 | private static array $cachedCloneables = []; | ||
50 | |||
51 | /** | ||
52 | * @phpstan-param class-string<T> $className | ||
53 | * | ||
54 | * @phpstan-return T | ||
55 | * | ||
56 | * @throws ExceptionInterface | ||
57 | * | ||
58 | * @template T of object | ||
59 | */ | ||
60 | public function instantiate(string $className): object | ||
61 | { | ||
62 | if (isset(self::$cachedCloneables[$className])) { | ||
63 | /** @phpstan-var T */ | ||
64 | $cachedCloneable = self::$cachedCloneables[$className]; | ||
65 | |||
66 | return clone $cachedCloneable; | ||
67 | } | ||
68 | |||
69 | if (isset(self::$cachedInstantiators[$className])) { | ||
70 | $factory = self::$cachedInstantiators[$className]; | ||
71 | |||
72 | return $factory(); | ||
73 | } | ||
74 | |||
75 | return $this->buildAndCacheFromFactory($className); | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * Builds the requested object and caches it in static properties for performance | ||
80 | * | ||
81 | * @phpstan-param class-string<T> $className | ||
82 | * | ||
83 | * @phpstan-return T | ||
84 | * | ||
85 | * @template T of object | ||
86 | */ | ||
87 | private function buildAndCacheFromFactory(string $className): object | ||
88 | { | ||
89 | $factory = self::$cachedInstantiators[$className] = $this->buildFactory($className); | ||
90 | $instance = $factory(); | ||
91 | |||
92 | if ($this->isSafeToClone(new ReflectionClass($instance))) { | ||
93 | self::$cachedCloneables[$className] = clone $instance; | ||
94 | } | ||
95 | |||
96 | return $instance; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * Builds a callable capable of instantiating the given $className without | ||
101 | * invoking its constructor. | ||
102 | * | ||
103 | * @phpstan-param class-string<T> $className | ||
104 | * | ||
105 | * @phpstan-return callable(): T | ||
106 | * | ||
107 | * @throws InvalidArgumentException | ||
108 | * @throws UnexpectedValueException | ||
109 | * @throws ReflectionException | ||
110 | * | ||
111 | * @template T of object | ||
112 | */ | ||
113 | private function buildFactory(string $className): callable | ||
114 | { | ||
115 | $reflectionClass = $this->getReflectionClass($className); | ||
116 | |||
117 | if ($this->isInstantiableViaReflection($reflectionClass)) { | ||
118 | return [$reflectionClass, 'newInstanceWithoutConstructor']; | ||
119 | } | ||
120 | |||
121 | $serializedString = sprintf( | ||
122 | '%s:%d:"%s":0:{}', | ||
123 | is_subclass_of($className, Serializable::class) ? self::SERIALIZATION_FORMAT_USE_UNSERIALIZER : self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER, | ||
124 | strlen($className), | ||
125 | $className, | ||
126 | ); | ||
127 | |||
128 | $this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString); | ||
129 | |||
130 | return static fn () => unserialize($serializedString); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * @phpstan-param class-string<T> $className | ||
135 | * | ||
136 | * @phpstan-return ReflectionClass<T> | ||
137 | * | ||
138 | * @throws InvalidArgumentException | ||
139 | * @throws ReflectionException | ||
140 | * | ||
141 | * @template T of object | ||
142 | */ | ||
143 | private function getReflectionClass(string $className): ReflectionClass | ||
144 | { | ||
145 | if (! class_exists($className)) { | ||
146 | throw InvalidArgumentException::fromNonExistingClass($className); | ||
147 | } | ||
148 | |||
149 | if (enum_exists($className, false)) { | ||
150 | throw InvalidArgumentException::fromEnum($className); | ||
151 | } | ||
152 | |||
153 | $reflection = new ReflectionClass($className); | ||
154 | |||
155 | if ($reflection->isAbstract()) { | ||
156 | throw InvalidArgumentException::fromAbstractClass($reflection); | ||
157 | } | ||
158 | |||
159 | return $reflection; | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * @phpstan-param ReflectionClass<T> $reflectionClass | ||
164 | * | ||
165 | * @throws UnexpectedValueException | ||
166 | * | ||
167 | * @template T of object | ||
168 | */ | ||
169 | private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, string $serializedString): void | ||
170 | { | ||
171 | set_error_handler(static function (int $code, string $message, string $file, int $line) use ($reflectionClass, &$error): bool { | ||
172 | $error = UnexpectedValueException::fromUncleanUnSerialization( | ||
173 | $reflectionClass, | ||
174 | $message, | ||
175 | $code, | ||
176 | $file, | ||
177 | $line, | ||
178 | ); | ||
179 | |||
180 | return true; | ||
181 | }); | ||
182 | |||
183 | try { | ||
184 | $this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString); | ||
185 | } finally { | ||
186 | restore_error_handler(); | ||
187 | } | ||
188 | |||
189 | if ($error) { | ||
190 | throw $error; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * @phpstan-param ReflectionClass<T> $reflectionClass | ||
196 | * | ||
197 | * @throws UnexpectedValueException | ||
198 | * | ||
199 | * @template T of object | ||
200 | */ | ||
201 | private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, string $serializedString): void | ||
202 | { | ||
203 | try { | ||
204 | unserialize($serializedString); | ||
205 | } catch (Exception $exception) { | ||
206 | throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * @phpstan-param ReflectionClass<T> $reflectionClass | ||
212 | * | ||
213 | * @template T of object | ||
214 | */ | ||
215 | private function isInstantiableViaReflection(ReflectionClass $reflectionClass): bool | ||
216 | { | ||
217 | return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal()); | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * Verifies whether the given class is to be considered internal | ||
222 | * | ||
223 | * @phpstan-param ReflectionClass<T> $reflectionClass | ||
224 | * | ||
225 | * @template T of object | ||
226 | */ | ||
227 | private function hasInternalAncestors(ReflectionClass $reflectionClass): bool | ||
228 | { | ||
229 | do { | ||
230 | if ($reflectionClass->isInternal()) { | ||
231 | return true; | ||
232 | } | ||
233 | |||
234 | $reflectionClass = $reflectionClass->getParentClass(); | ||
235 | } while ($reflectionClass); | ||
236 | |||
237 | return false; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * Checks if a class is cloneable | ||
242 | * | ||
243 | * Classes implementing `__clone` cannot be safely cloned, as that may cause side-effects. | ||
244 | * | ||
245 | * @phpstan-param ReflectionClass<T> $reflectionClass | ||
246 | * | ||
247 | * @template T of object | ||
248 | */ | ||
249 | private function isSafeToClone(ReflectionClass $reflectionClass): bool | ||
250 | { | ||
251 | return $reflectionClass->isCloneable() | ||
252 | && ! $reflectionClass->hasMethod('__clone') | ||
253 | && ! $reflectionClass->isSubclassOf(ArrayIterator::class); | ||
254 | } | ||
255 | } | ||
diff --git a/vendor/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php new file mode 100644 index 0000000..c6ebe35 --- /dev/null +++ b/vendor/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php | |||
@@ -0,0 +1,24 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\Instantiator; | ||
6 | |||
7 | use Doctrine\Instantiator\Exception\ExceptionInterface; | ||
8 | |||
9 | /** | ||
10 | * Instantiator provides utility methods to build objects without invoking their constructors | ||
11 | */ | ||
12 | interface InstantiatorInterface | ||
13 | { | ||
14 | /** | ||
15 | * @phpstan-param class-string<T> $className | ||
16 | * | ||
17 | * @phpstan-return T | ||
18 | * | ||
19 | * @throws ExceptionInterface | ||
20 | * | ||
21 | * @template T of object | ||
22 | */ | ||
23 | public function instantiate(string $className): object; | ||
24 | } | ||