File "Instantiator.php"
Full Path: /home/warrior1/public_html/plugins/mailpoet/vendor-prefixed/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php
File size: 4.15 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace MailPoetVendor\Doctrine\Instantiator;
if (!defined('ABSPATH')) exit;
use ArrayIterator;
use MailPoetVendor\Doctrine\Instantiator\Exception\ExceptionInterface;
use MailPoetVendor\Doctrine\Instantiator\Exception\InvalidArgumentException;
use MailPoetVendor\Doctrine\Instantiator\Exception\UnexpectedValueException;
use Exception;
use ReflectionClass;
use ReflectionException;
use Serializable;
use function class_exists;
use function enum_exists;
use function is_subclass_of;
use function restore_error_handler;
use function set_error_handler;
use function sprintf;
use function strlen;
use function unserialize;
use const PHP_VERSION_ID;
final class Instantiator implements InstantiatorInterface
{
public const SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C';
public const SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O';
private static $cachedInstantiators = [];
private static $cachedCloneables = [];
public function instantiate($className)
{
if (isset(self::$cachedCloneables[$className])) {
$cachedCloneable = self::$cachedCloneables[$className];
return clone $cachedCloneable;
}
if (isset(self::$cachedInstantiators[$className])) {
$factory = self::$cachedInstantiators[$className];
return $factory();
}
return $this->buildAndCacheFromFactory($className);
}
private function buildAndCacheFromFactory(string $className)
{
$factory = self::$cachedInstantiators[$className] = $this->buildFactory($className);
$instance = $factory();
if ($this->isSafeToClone(new ReflectionClass($instance))) {
self::$cachedCloneables[$className] = clone $instance;
}
return $instance;
}
private function buildFactory(string $className) : callable
{
$reflectionClass = $this->getReflectionClass($className);
if ($this->isInstantiableViaReflection($reflectionClass)) {
return [$reflectionClass, 'newInstanceWithoutConstructor'];
}
$serializedString = sprintf('%s:%d:"%s":0:{}', is_subclass_of($className, Serializable::class) ? self::SERIALIZATION_FORMAT_USE_UNSERIALIZER : self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER, strlen($className), $className);
$this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString);
return static function () use($serializedString) {
return unserialize($serializedString);
};
}
private function getReflectionClass(string $className) : ReflectionClass
{
if (!class_exists($className)) {
throw InvalidArgumentException::fromNonExistingClass($className);
}
if (PHP_VERSION_ID >= 80100 && enum_exists($className, \false)) {
throw InvalidArgumentException::fromEnum($className);
}
$reflection = new ReflectionClass($className);
if ($reflection->isAbstract()) {
throw InvalidArgumentException::fromAbstractClass($reflection);
}
return $reflection;
}
private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, string $serializedString) : void
{
set_error_handler(static function (int $code, string $message, string $file, int $line) use($reflectionClass, &$error) : bool {
$error = UnexpectedValueException::fromUncleanUnSerialization($reflectionClass, $message, $code, $file, $line);
return \true;
});
try {
$this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString);
} finally {
restore_error_handler();
}
if ($error) {
throw $error;
}
}
private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, string $serializedString) : void
{
try {
unserialize($serializedString);
} catch (Exception $exception) {
throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception);
}
}
private function isInstantiableViaReflection(ReflectionClass $reflectionClass) : bool
{
return !($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal());
}
private function hasInternalAncestors(ReflectionClass $reflectionClass) : bool
{
do {
if ($reflectionClass->isInternal()) {
return \true;
}
$reflectionClass = $reflectionClass->getParentClass();
} while ($reflectionClass);
return \false;
}
private function isSafeToClone(ReflectionClass $reflectionClass) : bool
{
return $reflectionClass->isCloneable() && !$reflectionClass->hasMethod('__clone') && !$reflectionClass->isSubclassOf(ArrayIterator::class);
}
}