init
This commit is contained in:
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use function class_exists;
|
||||
use function interface_exists;
|
||||
use function is_array;
|
||||
use function is_file;
|
||||
use function reset;
|
||||
use function spl_autoload_functions;
|
||||
use function spl_autoload_register;
|
||||
use function spl_autoload_unregister;
|
||||
use function str_replace;
|
||||
use function stream_resolve_include_path;
|
||||
use function strpos;
|
||||
use function trait_exists;
|
||||
use function trigger_error;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const E_USER_DEPRECATED;
|
||||
@trigger_error(ClassLoader::class . ' is deprecated.', E_USER_DEPRECATED);
|
||||
class ClassLoader
|
||||
{
|
||||
protected $fileExtension = '.php';
|
||||
protected $namespace;
|
||||
protected $includePath;
|
||||
protected $namespaceSeparator = '\\';
|
||||
public function __construct($ns = null, $includePath = null)
|
||||
{
|
||||
$this->namespace = $ns;
|
||||
$this->includePath = $includePath;
|
||||
}
|
||||
public function setNamespaceSeparator($sep)
|
||||
{
|
||||
$this->namespaceSeparator = $sep;
|
||||
}
|
||||
public function getNamespaceSeparator()
|
||||
{
|
||||
return $this->namespaceSeparator;
|
||||
}
|
||||
public function setIncludePath($includePath)
|
||||
{
|
||||
$this->includePath = $includePath;
|
||||
}
|
||||
public function getIncludePath()
|
||||
{
|
||||
return $this->includePath;
|
||||
}
|
||||
public function setFileExtension($fileExtension)
|
||||
{
|
||||
$this->fileExtension = $fileExtension;
|
||||
}
|
||||
public function getFileExtension()
|
||||
{
|
||||
return $this->fileExtension;
|
||||
}
|
||||
public function register()
|
||||
{
|
||||
spl_autoload_register([$this, 'loadClass']);
|
||||
}
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister([$this, 'loadClass']);
|
||||
}
|
||||
public function loadClass($className)
|
||||
{
|
||||
if (self::typeExists($className)) {
|
||||
return \true;
|
||||
}
|
||||
if (!$this->canLoadClass($className)) {
|
||||
return \false;
|
||||
}
|
||||
require ($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '') . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension;
|
||||
return self::typeExists($className);
|
||||
}
|
||||
public function canLoadClass($className)
|
||||
{
|
||||
if ($this->namespace !== null && strpos($className, $this->namespace . $this->namespaceSeparator) !== 0) {
|
||||
return \false;
|
||||
}
|
||||
$file = str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension;
|
||||
if ($this->includePath !== null) {
|
||||
return is_file($this->includePath . DIRECTORY_SEPARATOR . $file);
|
||||
}
|
||||
return stream_resolve_include_path($file) !== \false;
|
||||
}
|
||||
public static function classExists($className)
|
||||
{
|
||||
return self::typeExists($className, \true);
|
||||
}
|
||||
public static function getClassLoader($className)
|
||||
{
|
||||
foreach (spl_autoload_functions() as $loader) {
|
||||
if (!is_array($loader)) {
|
||||
continue;
|
||||
}
|
||||
$classLoader = reset($loader);
|
||||
if ($classLoader instanceof ClassLoader && $classLoader->canLoadClass($className)) {
|
||||
return $classLoader;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static function typeExists($type, $autoload = \false)
|
||||
{
|
||||
return class_exists($type, $autoload) || interface_exists($type, $autoload) || trait_exists($type, $autoload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use Exception;
|
||||
class CommonException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
interface Comparable
|
||||
{
|
||||
public function compareTo($other);
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Doctrine\Common\Proxy\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Doctrine\Common\Proxy\Exception\OutOfBoundsException;
|
||||
use MailPoetVendor\Doctrine\Common\Util\ClassUtils;
|
||||
use MailPoetVendor\Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use MailPoetVendor\Doctrine\Persistence\Mapping\ClassMetadataFactory;
|
||||
use function class_exists;
|
||||
use function file_exists;
|
||||
use function filemtime;
|
||||
use function in_array;
|
||||
abstract class AbstractProxyFactory
|
||||
{
|
||||
public const AUTOGENERATE_NEVER = 0;
|
||||
public const AUTOGENERATE_ALWAYS = 1;
|
||||
public const AUTOGENERATE_FILE_NOT_EXISTS = 2;
|
||||
public const AUTOGENERATE_EVAL = 3;
|
||||
public const AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED = 4;
|
||||
private const AUTOGENERATE_MODES = [self::AUTOGENERATE_NEVER, self::AUTOGENERATE_ALWAYS, self::AUTOGENERATE_FILE_NOT_EXISTS, self::AUTOGENERATE_EVAL, self::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED];
|
||||
private $metadataFactory;
|
||||
private $proxyGenerator;
|
||||
private $autoGenerate;
|
||||
private $definitions = [];
|
||||
public function __construct(ProxyGenerator $proxyGenerator, ClassMetadataFactory $metadataFactory, $autoGenerate)
|
||||
{
|
||||
$this->proxyGenerator = $proxyGenerator;
|
||||
$this->metadataFactory = $metadataFactory;
|
||||
$this->autoGenerate = (int) $autoGenerate;
|
||||
if (!in_array($this->autoGenerate, self::AUTOGENERATE_MODES, \true)) {
|
||||
throw InvalidArgumentException::invalidAutoGenerateMode($autoGenerate);
|
||||
}
|
||||
}
|
||||
public function getProxy($className, array $identifier)
|
||||
{
|
||||
$definition = $this->definitions[$className] ?? $this->getProxyDefinition($className);
|
||||
$fqcn = $definition->proxyClassName;
|
||||
$proxy = new $fqcn($definition->initializer, $definition->cloner);
|
||||
foreach ($definition->identifierFields as $idField) {
|
||||
if (!isset($identifier[$idField])) {
|
||||
throw OutOfBoundsException::missingPrimaryKeyValue($className, $idField);
|
||||
}
|
||||
$definition->reflectionFields[$idField]->setValue($proxy, $identifier[$idField]);
|
||||
}
|
||||
return $proxy;
|
||||
}
|
||||
public function generateProxyClasses(array $classes, $proxyDir = null)
|
||||
{
|
||||
$generated = 0;
|
||||
foreach ($classes as $class) {
|
||||
if ($this->skipClass($class)) {
|
||||
continue;
|
||||
}
|
||||
$proxyFileName = $this->proxyGenerator->getProxyFileName($class->getName(), $proxyDir);
|
||||
$this->proxyGenerator->generateProxyClass($class, $proxyFileName);
|
||||
$generated += 1;
|
||||
}
|
||||
return $generated;
|
||||
}
|
||||
public function resetUninitializedProxy(Proxy $proxy)
|
||||
{
|
||||
if ($proxy->__isInitialized()) {
|
||||
throw InvalidArgumentException::unitializedProxyExpected($proxy);
|
||||
}
|
||||
$className = ClassUtils::getClass($proxy);
|
||||
$definition = $this->definitions[$className] ?? $this->getProxyDefinition($className);
|
||||
$proxy->__setInitializer($definition->initializer);
|
||||
$proxy->__setCloner($definition->cloner);
|
||||
return $proxy;
|
||||
}
|
||||
private function getProxyDefinition($className)
|
||||
{
|
||||
$classMetadata = $this->metadataFactory->getMetadataFor($className);
|
||||
$className = $classMetadata->getName();
|
||||
// aliases and case sensitivity
|
||||
$this->definitions[$className] = $this->createProxyDefinition($className);
|
||||
$proxyClassName = $this->definitions[$className]->proxyClassName;
|
||||
if (!class_exists($proxyClassName, \false)) {
|
||||
$fileName = $this->proxyGenerator->getProxyFileName($className);
|
||||
switch ($this->autoGenerate) {
|
||||
case self::AUTOGENERATE_NEVER:
|
||||
require $fileName;
|
||||
break;
|
||||
case self::AUTOGENERATE_FILE_NOT_EXISTS:
|
||||
if (!file_exists($fileName)) {
|
||||
$this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
|
||||
}
|
||||
require $fileName;
|
||||
break;
|
||||
case self::AUTOGENERATE_ALWAYS:
|
||||
$this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
|
||||
require $fileName;
|
||||
break;
|
||||
case self::AUTOGENERATE_EVAL:
|
||||
$this->proxyGenerator->generateProxyClass($classMetadata, \false);
|
||||
break;
|
||||
case self::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED:
|
||||
if (!file_exists($fileName) || filemtime($fileName) < filemtime($classMetadata->getReflectionClass()->getFileName())) {
|
||||
$this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
|
||||
}
|
||||
require $fileName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $this->definitions[$className];
|
||||
}
|
||||
protected abstract function skipClass(ClassMetadata $metadata);
|
||||
protected abstract function createProxyDefinition($className);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use Closure;
|
||||
use MailPoetVendor\Doctrine\Common\Proxy\Exception\InvalidArgumentException;
|
||||
use function call_user_func;
|
||||
use function file_exists;
|
||||
use function is_callable;
|
||||
use function ltrim;
|
||||
use function spl_autoload_register;
|
||||
use function str_replace;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
class Autoloader
|
||||
{
|
||||
public static function resolveFile($proxyDir, $proxyNamespace, $className)
|
||||
{
|
||||
if (strpos($className, $proxyNamespace) !== 0) {
|
||||
throw InvalidArgumentException::notProxyClass($className, $proxyNamespace);
|
||||
}
|
||||
// remove proxy namespace from class name
|
||||
$classNameRelativeToProxyNamespace = substr($className, strlen($proxyNamespace));
|
||||
// remove namespace separators from remaining class name
|
||||
$fileName = str_replace('\\', '', $classNameRelativeToProxyNamespace);
|
||||
return $proxyDir . DIRECTORY_SEPARATOR . $fileName . '.php';
|
||||
}
|
||||
public static function register($proxyDir, $proxyNamespace, $notFoundCallback = null)
|
||||
{
|
||||
$proxyNamespace = ltrim($proxyNamespace, '\\');
|
||||
if ($notFoundCallback !== null && !is_callable($notFoundCallback)) {
|
||||
throw InvalidArgumentException::invalidClassNotFoundCallback($notFoundCallback);
|
||||
}
|
||||
$autoloader = static function ($className) use($proxyDir, $proxyNamespace, $notFoundCallback) {
|
||||
if ($proxyNamespace === '') {
|
||||
return;
|
||||
}
|
||||
if (strpos($className, $proxyNamespace) !== 0) {
|
||||
return;
|
||||
}
|
||||
$file = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className);
|
||||
if ($notFoundCallback && !file_exists($file)) {
|
||||
call_user_func($notFoundCallback, $proxyDir, $proxyNamespace, $className);
|
||||
}
|
||||
require $file;
|
||||
};
|
||||
spl_autoload_register($autoloader);
|
||||
return $autoloader;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Doctrine\Persistence\Proxy;
|
||||
use InvalidArgumentException as BaseInvalidArgumentException;
|
||||
use function get_class;
|
||||
use function gettype;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
class InvalidArgumentException extends BaseInvalidArgumentException implements ProxyException
|
||||
{
|
||||
public static function proxyDirectoryRequired()
|
||||
{
|
||||
return new self('You must configure a proxy directory. See docs for details');
|
||||
}
|
||||
public static function notProxyClass($className, $proxyNamespace)
|
||||
{
|
||||
return new self(sprintf('The class "%s" is not part of the proxy namespace "%s"', $className, $proxyNamespace));
|
||||
}
|
||||
public static function invalidPlaceholder($name)
|
||||
{
|
||||
return new self(sprintf('Provided placeholder for "%s" must be either a string or a valid callable', $name));
|
||||
}
|
||||
public static function proxyNamespaceRequired()
|
||||
{
|
||||
return new self('You must configure a proxy namespace');
|
||||
}
|
||||
public static function unitializedProxyExpected(Proxy $proxy)
|
||||
{
|
||||
return new self(sprintf('Provided proxy of type "%s" must not be initialized.', get_class($proxy)));
|
||||
}
|
||||
public static function invalidClassNotFoundCallback($callback)
|
||||
{
|
||||
$type = is_object($callback) ? get_class($callback) : gettype($callback);
|
||||
return new self(sprintf('Invalid \\$notFoundCallback given: must be a callable, "%s" given', $type));
|
||||
}
|
||||
public static function classMustNotBeAbstract($className)
|
||||
{
|
||||
return new self(sprintf('Unable to create a proxy for an abstract class "%s".', $className));
|
||||
}
|
||||
public static function classMustNotBeFinal($className)
|
||||
{
|
||||
return new self(sprintf('Unable to create a proxy for a final class "%s".', $className));
|
||||
}
|
||||
public static function classMustNotBeReadOnly($className)
|
||||
{
|
||||
return new self(sprintf('Unable to create a proxy for a readonly class "%s".', $className));
|
||||
}
|
||||
public static function invalidAutoGenerateMode($value) : self
|
||||
{
|
||||
return new self(sprintf('Invalid auto generate mode "%s" given.', $value));
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use OutOfBoundsException as BaseOutOfBoundsException;
|
||||
use function sprintf;
|
||||
class OutOfBoundsException extends BaseOutOfBoundsException implements ProxyException
|
||||
{
|
||||
public static function missingPrimaryKeyValue($className, $idField)
|
||||
{
|
||||
return new self(sprintf('Missing value for primary key %s on %s', $idField, $className));
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
interface ProxyException
|
||||
{
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy\Exception;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use Throwable;
|
||||
use UnexpectedValueException as BaseUnexpectedValueException;
|
||||
use function sprintf;
|
||||
class UnexpectedValueException extends BaseUnexpectedValueException implements ProxyException
|
||||
{
|
||||
public static function proxyDirectoryNotWritable($proxyDirectory)
|
||||
{
|
||||
return new self(sprintf('Your proxy directory "%s" must be writable', $proxyDirectory));
|
||||
}
|
||||
public static function invalidParameterTypeHint($className, $methodName, $parameterName, ?Throwable $previous = null)
|
||||
{
|
||||
return new self(sprintf('The type hint of parameter "%s" in method "%s" in class "%s" is invalid.', $parameterName, $methodName, $className), 0, $previous);
|
||||
}
|
||||
public static function invalidReturnTypeHint($className, $methodName, ?Throwable $previous = null)
|
||||
{
|
||||
return new self(sprintf('The return type of method "%s" in class "%s" is invalid.', $methodName, $className), 0, $previous);
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use Closure;
|
||||
use MailPoetVendor\Doctrine\Persistence\Proxy as BaseProxy;
|
||||
interface Proxy extends BaseProxy
|
||||
{
|
||||
public function __setInitialized($initialized);
|
||||
public function __setInitializer(?Closure $initializer = null);
|
||||
public function __getInitializer();
|
||||
public function __setCloner(?Closure $cloner = null);
|
||||
public function __getCloner();
|
||||
public function __getLazyProperties();
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use ReflectionProperty;
|
||||
class ProxyDefinition
|
||||
{
|
||||
public $proxyClassName;
|
||||
public $identifierFields;
|
||||
public $reflectionFields;
|
||||
public $initializer;
|
||||
public $cloner;
|
||||
public function __construct($proxyClassName, array $identifierFields, array $reflectionFields, $initializer, $cloner)
|
||||
{
|
||||
$this->proxyClassName = $proxyClassName;
|
||||
$this->identifierFields = $identifierFields;
|
||||
$this->reflectionFields = $reflectionFields;
|
||||
$this->initializer = $initializer;
|
||||
$this->cloner = $cloner;
|
||||
}
|
||||
}
|
||||
+733
@@ -0,0 +1,733 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Proxy;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use BackedEnum;
|
||||
use MailPoetVendor\Doctrine\Common\Proxy\Exception\InvalidArgumentException;
|
||||
use MailPoetVendor\Doctrine\Common\Proxy\Exception\UnexpectedValueException;
|
||||
use MailPoetVendor\Doctrine\Common\Util\ClassUtils;
|
||||
use MailPoetVendor\Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use ReflectionIntersectionType;
|
||||
use ReflectionMethod;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use ReflectionType;
|
||||
use ReflectionUnionType;
|
||||
use function array_combine;
|
||||
use function array_diff;
|
||||
use function array_key_exists;
|
||||
use function array_map;
|
||||
use function array_slice;
|
||||
use function array_unique;
|
||||
use function assert;
|
||||
use function bin2hex;
|
||||
use function call_user_func;
|
||||
use function chmod;
|
||||
use function class_exists;
|
||||
use function dirname;
|
||||
use function explode;
|
||||
use function file;
|
||||
use function file_put_contents;
|
||||
use function get_class;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function interface_exists;
|
||||
use function is_callable;
|
||||
use function is_dir;
|
||||
use function is_scalar;
|
||||
use function is_string;
|
||||
use function is_writable;
|
||||
use function lcfirst;
|
||||
use function ltrim;
|
||||
use function method_exists;
|
||||
use function mkdir;
|
||||
use function preg_match;
|
||||
use function preg_match_all;
|
||||
use function preg_replace;
|
||||
use function preg_split;
|
||||
use function random_bytes;
|
||||
use function rename;
|
||||
use function rtrim;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
use function strrev;
|
||||
use function strtolower;
|
||||
use function strtr;
|
||||
use function substr;
|
||||
use function trim;
|
||||
use function var_export;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_VERSION_ID;
|
||||
use const PREG_SPLIT_DELIM_CAPTURE;
|
||||
class ProxyGenerator
|
||||
{
|
||||
public const PATTERN_MATCH_ID_METHOD = <<<'EOT'
|
||||
((?(DEFINE)
|
||||
(?<type>\\?[a-z_\x7f-\xff][\w\x7f-\xff]*(?:\\[a-z_\x7f-\xff][\w\x7f-\xff]*)*)
|
||||
(?<intersection_type>(?&type)\s*&\s*(?&type))
|
||||
(?<union_type>(?:(?:\(\s*(?&intersection_type)\s*\))|(?&type))(?:\s*\|\s*(?:(?:\(\s*(?&intersection_type)\s*\))|(?&type)))+)
|
||||
)(?:public\s+)?(?:function\s+%s\s*\(\)\s*)\s*(?::\s*(?:(?&union_type)|(?&intersection_type)|(?:\??(?&type)))\s*)?{\s*return\s*\$this->%s;\s*})i
|
||||
EOT;
|
||||
private $proxyNamespace;
|
||||
private $proxyDirectory;
|
||||
protected $placeholders = ['baseProxyInterface' => Proxy::class, 'additionalProperties' => ''];
|
||||
protected $proxyClassTemplate = '<?php
|
||||
namespace <namespace>;
|
||||
<enumUseStatements>
|
||||
class <proxyShortClassName> extends \\<className> implements \\<baseProxyInterface>
|
||||
{
|
||||
public $__initializer__;
|
||||
public $__cloner__;
|
||||
public $__isInitialized__ = false;
|
||||
public static $lazyPropertiesNames = <lazyPropertiesNames>;
|
||||
public static $lazyPropertiesDefaults = <lazyPropertiesDefaults>;
|
||||
<additionalProperties>
|
||||
<constructorImpl>
|
||||
<magicGet>
|
||||
<magicSet>
|
||||
<magicIsset>
|
||||
<sleepImpl>
|
||||
<wakeupImpl>
|
||||
<cloneImpl>
|
||||
public function __load(): void
|
||||
{
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, \'__load\', []);
|
||||
}
|
||||
public function __isInitialized(): bool
|
||||
{
|
||||
return $this->__isInitialized__;
|
||||
}
|
||||
public function __setInitialized($initialized): void
|
||||
{
|
||||
$this->__isInitialized__ = $initialized;
|
||||
}
|
||||
public function __setInitializer(?\\Closure $initializer = null): void
|
||||
{
|
||||
$this->__initializer__ = $initializer;
|
||||
}
|
||||
public function __getInitializer(): ?\\Closure
|
||||
{
|
||||
return $this->__initializer__;
|
||||
}
|
||||
public function __setCloner(?\\Closure $cloner = null): void
|
||||
{
|
||||
$this->__cloner__ = $cloner;
|
||||
}
|
||||
public function __getCloner(): ?\\Closure
|
||||
{
|
||||
return $this->__cloner__;
|
||||
}
|
||||
public function __getLazyProperties(): array
|
||||
{
|
||||
return self::$lazyPropertiesDefaults;
|
||||
}
|
||||
<methods>
|
||||
}
|
||||
';
|
||||
public function __construct($proxyDirectory, $proxyNamespace)
|
||||
{
|
||||
if (!$proxyDirectory) {
|
||||
throw InvalidArgumentException::proxyDirectoryRequired();
|
||||
}
|
||||
if (!$proxyNamespace) {
|
||||
throw InvalidArgumentException::proxyNamespaceRequired();
|
||||
}
|
||||
$this->proxyDirectory = $proxyDirectory;
|
||||
$this->proxyNamespace = $proxyNamespace;
|
||||
}
|
||||
public function setPlaceholder($name, $placeholder)
|
||||
{
|
||||
if (!is_string($placeholder) && !is_callable($placeholder)) {
|
||||
throw InvalidArgumentException::invalidPlaceholder($name);
|
||||
}
|
||||
$this->placeholders[$name] = $placeholder;
|
||||
}
|
||||
public function setProxyClassTemplate($proxyClassTemplate)
|
||||
{
|
||||
$this->proxyClassTemplate = (string) $proxyClassTemplate;
|
||||
}
|
||||
public function generateProxyClass(ClassMetadata $class, $fileName = \false)
|
||||
{
|
||||
$this->verifyClassCanBeProxied($class);
|
||||
preg_match_all('(<([a-zA-Z]+)>)', $this->proxyClassTemplate, $placeholderMatches);
|
||||
$placeholderMatches = array_combine($placeholderMatches[0], $placeholderMatches[1]);
|
||||
$placeholders = [];
|
||||
foreach ($placeholderMatches as $placeholder => $name) {
|
||||
$placeholders[$placeholder] = $this->placeholders[$name] ?? [$this, 'generate' . $name];
|
||||
}
|
||||
foreach ($placeholders as &$placeholder) {
|
||||
if (!is_callable($placeholder)) {
|
||||
continue;
|
||||
}
|
||||
$placeholder = call_user_func($placeholder, $class);
|
||||
}
|
||||
$proxyCode = strtr($this->proxyClassTemplate, $placeholders);
|
||||
if (!$fileName) {
|
||||
$proxyClassName = $this->generateNamespace($class) . '\\' . $this->generateProxyShortClassName($class);
|
||||
if (!class_exists($proxyClassName)) {
|
||||
eval(substr($proxyCode, 5));
|
||||
}
|
||||
return;
|
||||
}
|
||||
$parentDirectory = dirname($fileName);
|
||||
if (!is_dir($parentDirectory) && @mkdir($parentDirectory, 0775, \true) === \false) {
|
||||
throw UnexpectedValueException::proxyDirectoryNotWritable($this->proxyDirectory);
|
||||
}
|
||||
if (!is_writable($parentDirectory)) {
|
||||
throw UnexpectedValueException::proxyDirectoryNotWritable($this->proxyDirectory);
|
||||
}
|
||||
$tmpFileName = $fileName . '.' . bin2hex(random_bytes(12));
|
||||
file_put_contents($tmpFileName, $proxyCode);
|
||||
@chmod($tmpFileName, 0664);
|
||||
rename($tmpFileName, $fileName);
|
||||
}
|
||||
private function verifyClassCanBeProxied(ClassMetadata $class)
|
||||
{
|
||||
if ($class->getReflectionClass()->isFinal()) {
|
||||
throw InvalidArgumentException::classMustNotBeFinal($class->getName());
|
||||
}
|
||||
if ($class->getReflectionClass()->isAbstract()) {
|
||||
throw InvalidArgumentException::classMustNotBeAbstract($class->getName());
|
||||
}
|
||||
if (PHP_VERSION_ID >= 80200 && $class->getReflectionClass()->isReadOnly()) {
|
||||
throw InvalidArgumentException::classMustNotBeReadOnly($class->getName());
|
||||
}
|
||||
}
|
||||
private function generateProxyShortClassName(ClassMetadata $class)
|
||||
{
|
||||
$proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace);
|
||||
$parts = explode('\\', strrev($proxyClassName), 2);
|
||||
return strrev($parts[0]);
|
||||
}
|
||||
private function generateNamespace(ClassMetadata $class)
|
||||
{
|
||||
$proxyClassName = ClassUtils::generateProxyClassName($class->getName(), $this->proxyNamespace);
|
||||
$parts = explode('\\', strrev($proxyClassName), 2);
|
||||
return strrev($parts[1]);
|
||||
}
|
||||
public function generateEnumUseStatements(ClassMetadata $class) : string
|
||||
{
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
return "\n";
|
||||
}
|
||||
$defaultProperties = $class->getReflectionClass()->getDefaultProperties();
|
||||
$lazyLoadedPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
|
||||
$enumClasses = [];
|
||||
foreach ($class->getReflectionClass()->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
|
||||
$name = $property->getName();
|
||||
if (!in_array($name, $lazyLoadedPublicProperties, \true)) {
|
||||
continue;
|
||||
}
|
||||
if (array_key_exists($name, $defaultProperties) && $defaultProperties[$name] instanceof BackedEnum) {
|
||||
$enumClassNameParts = explode('\\', get_class($defaultProperties[$name]));
|
||||
$enumClasses[] = $enumClassNameParts[0];
|
||||
}
|
||||
}
|
||||
return implode("\n", array_map(static function ($className) {
|
||||
return 'use ' . $className . ';';
|
||||
}, array_unique($enumClasses))) . "\n";
|
||||
}
|
||||
private function generateClassName(ClassMetadata $class)
|
||||
{
|
||||
return ltrim($class->getName(), '\\');
|
||||
}
|
||||
private function generateLazyPropertiesNames(ClassMetadata $class)
|
||||
{
|
||||
$lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
|
||||
$values = [];
|
||||
foreach ($lazyPublicProperties as $name) {
|
||||
$values[$name] = null;
|
||||
}
|
||||
return var_export($values, \true);
|
||||
}
|
||||
private function generateLazyPropertiesDefaults(ClassMetadata $class)
|
||||
{
|
||||
return var_export($this->getLazyLoadedPublicProperties($class), \true);
|
||||
}
|
||||
private function generateConstructorImpl(ClassMetadata $class)
|
||||
{
|
||||
$constructorImpl = <<<'EOT'
|
||||
public function __construct(?\Closure $initializer = null, ?\Closure $cloner = null)
|
||||
{
|
||||
EOT;
|
||||
$toUnset = array_map(static function (string $name) : string {
|
||||
return '$this->' . $name;
|
||||
}, $this->getLazyLoadedPublicPropertiesNames($class));
|
||||
return $constructorImpl . ($toUnset === [] ? '' : ' unset(' . implode(', ', $toUnset) . ");\n") . <<<'EOT'
|
||||
$this->__initializer__ = $initializer;
|
||||
$this->__cloner__ = $cloner;
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
private function generateMagicGet(ClassMetadata $class)
|
||||
{
|
||||
$lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
|
||||
$reflectionClass = $class->getReflectionClass();
|
||||
$hasParentGet = \false;
|
||||
$returnReference = '';
|
||||
$inheritDoc = '';
|
||||
$name = '$name';
|
||||
$parametersString = '$name';
|
||||
$returnTypeHint = null;
|
||||
if ($reflectionClass->hasMethod('__get')) {
|
||||
$hasParentGet = \true;
|
||||
$inheritDoc = '{@inheritDoc}';
|
||||
$methodReflection = $reflectionClass->getMethod('__get');
|
||||
if ($methodReflection->returnsReference()) {
|
||||
$returnReference = '& ';
|
||||
}
|
||||
$methodParameters = $methodReflection->getParameters();
|
||||
$name = '$' . $methodParameters[0]->getName();
|
||||
$parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name']);
|
||||
$returnTypeHint = $this->getMethodReturnType($methodReflection);
|
||||
}
|
||||
if (empty($lazyPublicProperties) && !$hasParentGet) {
|
||||
return '';
|
||||
}
|
||||
$magicGet = <<<EOT
|
||||
public function {$returnReference}__get({$parametersString}){$returnTypeHint}
|
||||
{
|
||||
EOT;
|
||||
if (!empty($lazyPublicProperties)) {
|
||||
$magicGet .= <<<'EOT'
|
||||
if (\array_key_exists($name, self::$lazyPropertiesNames)) {
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]);
|
||||
EOT;
|
||||
if ($returnTypeHint === ': void') {
|
||||
$magicGet .= "\n return;";
|
||||
} else {
|
||||
$magicGet .= "\n return \$this->\$name;";
|
||||
}
|
||||
$magicGet .= <<<'EOT'
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
if ($hasParentGet) {
|
||||
$magicGet .= <<<'EOT'
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]);
|
||||
EOT;
|
||||
if ($returnTypeHint === ': void') {
|
||||
$magicGet .= <<<'EOT'
|
||||
parent::__get($name);
|
||||
return;
|
||||
EOT;
|
||||
} elseif ($returnTypeHint === ': never') {
|
||||
$magicGet .= <<<'EOT'
|
||||
parent::__get($name);
|
||||
EOT;
|
||||
} else {
|
||||
$magicGet .= <<<'EOT'
|
||||
return parent::__get($name);
|
||||
EOT;
|
||||
}
|
||||
} else {
|
||||
$magicGet .= sprintf(<<<EOT
|
||||
trigger_error(sprintf('Undefined property: %%s::\$%%s', __CLASS__, %s), E_USER_NOTICE);
|
||||
EOT
|
||||
, $name);
|
||||
}
|
||||
return $magicGet . "\n }";
|
||||
}
|
||||
private function generateMagicSet(ClassMetadata $class)
|
||||
{
|
||||
$lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
|
||||
$reflectionClass = $class->getReflectionClass();
|
||||
$hasParentSet = \false;
|
||||
$inheritDoc = '';
|
||||
$parametersString = '$name, $value';
|
||||
$returnTypeHint = null;
|
||||
if ($reflectionClass->hasMethod('__set')) {
|
||||
$hasParentSet = \true;
|
||||
$inheritDoc = '{@inheritDoc}';
|
||||
$methodReflection = $reflectionClass->getMethod('__set');
|
||||
$parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name', 'value']);
|
||||
$returnTypeHint = $this->getMethodReturnType($methodReflection);
|
||||
}
|
||||
if (empty($lazyPublicProperties) && !$hasParentSet) {
|
||||
return '';
|
||||
}
|
||||
$magicSet = <<<EOT
|
||||
public function __set({$parametersString}){$returnTypeHint}
|
||||
{
|
||||
EOT;
|
||||
if (!empty($lazyPublicProperties)) {
|
||||
$magicSet .= <<<'EOT'
|
||||
if (\array_key_exists($name, self::$lazyPropertiesNames)) {
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, '__set', [$name, $value]);
|
||||
$this->$name = $value;
|
||||
return;
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
if ($hasParentSet) {
|
||||
$magicSet .= <<<'EOT'
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, '__set', [$name, $value]);
|
||||
EOT;
|
||||
if ($returnTypeHint === ': void') {
|
||||
$magicSet .= <<<'EOT'
|
||||
parent::__set($name, $value);
|
||||
return;
|
||||
EOT;
|
||||
} elseif ($returnTypeHint === ': never') {
|
||||
$magicSet .= <<<'EOT'
|
||||
parent::__set($name, $value);
|
||||
EOT;
|
||||
} else {
|
||||
$magicSet .= <<<'EOT'
|
||||
return parent::__set($name, $value);
|
||||
EOT;
|
||||
}
|
||||
} else {
|
||||
$magicSet .= ' $this->$name = $value;';
|
||||
}
|
||||
return $magicSet . "\n }";
|
||||
}
|
||||
private function generateMagicIsset(ClassMetadata $class)
|
||||
{
|
||||
$lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
|
||||
$hasParentIsset = $class->getReflectionClass()->hasMethod('__isset');
|
||||
$parametersString = '$name';
|
||||
$returnTypeHint = null;
|
||||
if ($hasParentIsset) {
|
||||
$methodReflection = $class->getReflectionClass()->getMethod('__isset');
|
||||
$parametersString = $this->buildParametersString($methodReflection->getParameters(), ['name']);
|
||||
$returnTypeHint = $this->getMethodReturnType($methodReflection);
|
||||
}
|
||||
if (empty($lazyPublicProperties) && !$hasParentIsset) {
|
||||
return '';
|
||||
}
|
||||
$inheritDoc = $hasParentIsset ? '{@inheritDoc}' : '';
|
||||
$magicIsset = <<<EOT
|
||||
public function __isset({$parametersString}){$returnTypeHint}
|
||||
{
|
||||
EOT;
|
||||
if (!empty($lazyPublicProperties)) {
|
||||
$magicIsset .= <<<'EOT'
|
||||
if (\array_key_exists($name, self::$lazyPropertiesNames)) {
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', [$name]);
|
||||
return isset($this->$name);
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
if ($hasParentIsset) {
|
||||
$magicIsset .= <<<'EOT'
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, '__isset', [$name]);
|
||||
return parent::__isset($name);
|
||||
EOT;
|
||||
} else {
|
||||
$magicIsset .= ' return false;';
|
||||
}
|
||||
return $magicIsset . "\n }";
|
||||
}
|
||||
private function generateSleepImpl(ClassMetadata $class)
|
||||
{
|
||||
$reflectionClass = $class->getReflectionClass();
|
||||
$hasParentSleep = $reflectionClass->hasMethod('__sleep');
|
||||
$inheritDoc = $hasParentSleep ? '{@inheritDoc}' : '';
|
||||
$returnTypeHint = $hasParentSleep ? $this->getMethodReturnType($reflectionClass->getMethod('__sleep')) : '';
|
||||
$sleepImpl = <<<EOT
|
||||
public function __sleep(){$returnTypeHint}
|
||||
{
|
||||
EOT;
|
||||
if ($hasParentSleep) {
|
||||
return $sleepImpl . <<<'EOT'
|
||||
$properties = array_merge(['__isInitialized__'], parent::__sleep());
|
||||
if ($this->__isInitialized__) {
|
||||
$properties = array_diff($properties, array_keys(self::$lazyPropertiesNames));
|
||||
}
|
||||
return $properties;
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
$allProperties = ['__isInitialized__'];
|
||||
foreach ($class->getReflectionClass()->getProperties() as $prop) {
|
||||
assert($prop instanceof ReflectionProperty);
|
||||
if ($prop->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
$allProperties[] = $prop->isPrivate() ? "\x00" . $prop->getDeclaringClass()->getName() . "\x00" . $prop->getName() : $prop->getName();
|
||||
}
|
||||
$lazyPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
|
||||
$protectedProperties = array_diff($allProperties, $lazyPublicProperties);
|
||||
foreach ($allProperties as &$property) {
|
||||
$property = var_export($property, \true);
|
||||
}
|
||||
foreach ($protectedProperties as &$property) {
|
||||
$property = var_export($property, \true);
|
||||
}
|
||||
$allProperties = implode(', ', $allProperties);
|
||||
$protectedProperties = implode(', ', $protectedProperties);
|
||||
return $sleepImpl . <<<EOT
|
||||
if (\$this->__isInitialized__) {
|
||||
return [{$allProperties}];
|
||||
}
|
||||
return [{$protectedProperties}];
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
private function generateWakeupImpl(ClassMetadata $class)
|
||||
{
|
||||
$reflectionClass = $class->getReflectionClass();
|
||||
$hasParentWakeup = $reflectionClass->hasMethod('__wakeup');
|
||||
$unsetPublicProperties = [];
|
||||
foreach ($this->getLazyLoadedPublicPropertiesNames($class) as $lazyPublicProperty) {
|
||||
$unsetPublicProperties[] = '$this->' . $lazyPublicProperty;
|
||||
}
|
||||
$shortName = $this->generateProxyShortClassName($class);
|
||||
$inheritDoc = $hasParentWakeup ? '{@inheritDoc}' : '';
|
||||
$returnTypeHint = $hasParentWakeup ? $this->getMethodReturnType($reflectionClass->getMethod('__wakeup')) : '';
|
||||
$wakeupImpl = <<<EOT
|
||||
public function __wakeup(){$returnTypeHint}
|
||||
{
|
||||
if ( ! \$this->__isInitialized__) {
|
||||
\$this->__initializer__ = function ({$shortName} \$proxy) {
|
||||
\$proxy->__setInitializer(null);
|
||||
\$proxy->__setCloner(null);
|
||||
\$existingProperties = get_object_vars(\$proxy);
|
||||
foreach (\$proxy::\$lazyPropertiesDefaults as \$property => \$defaultValue) {
|
||||
if ( ! array_key_exists(\$property, \$existingProperties)) {
|
||||
\$proxy->\$property = \$defaultValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
EOT;
|
||||
if (!empty($unsetPublicProperties)) {
|
||||
$wakeupImpl .= "\n unset(" . implode(', ', $unsetPublicProperties) . ');';
|
||||
}
|
||||
$wakeupImpl .= "\n }";
|
||||
if ($hasParentWakeup) {
|
||||
$wakeupImpl .= "\n parent::__wakeup();";
|
||||
}
|
||||
$wakeupImpl .= "\n }";
|
||||
return $wakeupImpl;
|
||||
}
|
||||
private function generateCloneImpl(ClassMetadata $class)
|
||||
{
|
||||
$reflectionClass = $class->getReflectionClass();
|
||||
$hasParentClone = $reflectionClass->hasMethod('__clone');
|
||||
$returnTypeHint = $hasParentClone ? $this->getMethodReturnType($reflectionClass->getMethod('__clone')) : '';
|
||||
$inheritDoc = $hasParentClone ? '{@inheritDoc}' : '';
|
||||
$callParentClone = $hasParentClone ? "\n parent::__clone();\n" : '';
|
||||
return <<<EOT
|
||||
public function __clone(){$returnTypeHint}
|
||||
{
|
||||
\$this->__cloner__ && \$this->__cloner__->__invoke(\$this, '__clone', []);
|
||||
{$callParentClone} }
|
||||
EOT;
|
||||
}
|
||||
private function generateMethods(ClassMetadata $class)
|
||||
{
|
||||
$methods = '';
|
||||
$methodNames = [];
|
||||
$reflectionMethods = $class->getReflectionClass()->getMethods(ReflectionMethod::IS_PUBLIC);
|
||||
$skippedMethods = ['__sleep' => \true, '__clone' => \true, '__wakeup' => \true, '__get' => \true, '__set' => \true, '__isset' => \true];
|
||||
foreach ($reflectionMethods as $method) {
|
||||
$name = $method->getName();
|
||||
if ($method->isConstructor() || isset($skippedMethods[strtolower($name)]) || isset($methodNames[$name]) || $method->isFinal() || $method->isStatic() || !$method->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
$methodNames[$name] = \true;
|
||||
$methods .= "\n /**\n" . " * {@inheritDoc}\n" . " */\n" . ' public function ';
|
||||
if ($method->returnsReference()) {
|
||||
$methods .= '&';
|
||||
}
|
||||
$methods .= $name . '(' . $this->buildParametersString($method->getParameters()) . ')';
|
||||
$methods .= $this->getMethodReturnType($method);
|
||||
$methods .= "\n" . ' {' . "\n";
|
||||
if ($this->isShortIdentifierGetter($method, $class)) {
|
||||
$identifier = lcfirst(substr($name, 3));
|
||||
$fieldType = $class->getTypeOfField($identifier);
|
||||
$cast = in_array($fieldType, ['integer', 'smallint'], \true) ? '(int) ' : '';
|
||||
$methods .= ' if ($this->__isInitialized__ === false) {' . "\n";
|
||||
$methods .= ' ';
|
||||
$methods .= $this->shouldProxiedMethodReturn($method) ? 'return ' : '';
|
||||
$methods .= $cast . ' parent::' . $method->getName() . "();\n";
|
||||
$methods .= ' }' . "\n\n";
|
||||
}
|
||||
$invokeParamsString = implode(', ', $this->getParameterNamesForInvoke($method->getParameters()));
|
||||
$callParamsString = implode(', ', $this->getParameterNamesForParentCall($method->getParameters()));
|
||||
$methods .= "\n \$this->__initializer__ " . '&& $this->__initializer__->__invoke($this, ' . var_export($name, \true) . ', [' . $invokeParamsString . ']);' . "\n\n " . ($this->shouldProxiedMethodReturn($method) ? 'return ' : '') . 'parent::' . $name . '(' . $callParamsString . ');' . "\n" . ' }' . "\n";
|
||||
}
|
||||
return $methods;
|
||||
}
|
||||
public function getProxyFileName($className, $baseDirectory = null)
|
||||
{
|
||||
$baseDirectory = $baseDirectory ?: $this->proxyDirectory;
|
||||
return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . Proxy::MARKER . str_replace('\\', '', $className) . '.php';
|
||||
}
|
||||
private function isShortIdentifierGetter($method, ClassMetadata $class)
|
||||
{
|
||||
$identifier = lcfirst(substr($method->getName(), 3));
|
||||
$startLine = $method->getStartLine();
|
||||
$endLine = $method->getEndLine();
|
||||
$cheapCheck = $method->getNumberOfParameters() === 0 && substr($method->getName(), 0, 3) === 'get' && in_array($identifier, $class->getIdentifier(), \true) && $class->hasField($identifier) && $endLine - $startLine <= 4;
|
||||
if ($cheapCheck) {
|
||||
$code = file($method->getFileName());
|
||||
$code = trim(implode(' ', array_slice($code, $startLine - 1, $endLine - $startLine + 1)));
|
||||
$pattern = sprintf(self::PATTERN_MATCH_ID_METHOD, $method->getName(), $identifier);
|
||||
if (preg_match($pattern, $code)) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
private function getLazyLoadedPublicPropertiesNames(ClassMetadata $class) : array
|
||||
{
|
||||
$properties = [];
|
||||
foreach ($class->getReflectionClass()->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
|
||||
$name = $property->getName();
|
||||
if (!$class->hasField($name) && !$class->hasAssociation($name) || $class->isIdentifier($name)) {
|
||||
continue;
|
||||
}
|
||||
$properties[] = $name;
|
||||
}
|
||||
return $properties;
|
||||
}
|
||||
private function getLazyLoadedPublicProperties(ClassMetadata $class)
|
||||
{
|
||||
$defaultProperties = $class->getReflectionClass()->getDefaultProperties();
|
||||
$lazyLoadedPublicProperties = $this->getLazyLoadedPublicPropertiesNames($class);
|
||||
$defaultValues = [];
|
||||
foreach ($class->getReflectionClass()->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
|
||||
$name = $property->getName();
|
||||
if (!in_array($name, $lazyLoadedPublicProperties, \true)) {
|
||||
continue;
|
||||
}
|
||||
if (array_key_exists($name, $defaultProperties)) {
|
||||
$defaultValues[$name] = $defaultProperties[$name];
|
||||
} elseif (method_exists($property, 'getType')) {
|
||||
$propertyType = $property->getType();
|
||||
if ($propertyType !== null && $propertyType->allowsNull()) {
|
||||
$defaultValues[$name] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $defaultValues;
|
||||
}
|
||||
private function buildParametersString(array $parameters, array $renameParameters = [])
|
||||
{
|
||||
$parameterDefinitions = [];
|
||||
$i = -1;
|
||||
foreach ($parameters as $param) {
|
||||
assert($param instanceof ReflectionParameter);
|
||||
$i++;
|
||||
$parameterDefinition = '';
|
||||
$parameterType = $this->getParameterType($param);
|
||||
if ($parameterType !== null) {
|
||||
$parameterDefinition .= $parameterType . ' ';
|
||||
}
|
||||
if ($param->isPassedByReference()) {
|
||||
$parameterDefinition .= '&';
|
||||
}
|
||||
if ($param->isVariadic()) {
|
||||
$parameterDefinition .= '...';
|
||||
}
|
||||
$parameterDefinition .= '$' . ($renameParameters ? $renameParameters[$i] : $param->getName());
|
||||
$parameterDefinition .= $this->getParameterDefaultValue($param);
|
||||
$parameterDefinitions[] = $parameterDefinition;
|
||||
}
|
||||
return implode(', ', $parameterDefinitions);
|
||||
}
|
||||
private function getParameterType(ReflectionParameter $parameter)
|
||||
{
|
||||
if (!$parameter->hasType()) {
|
||||
return null;
|
||||
}
|
||||
$declaringFunction = $parameter->getDeclaringFunction();
|
||||
assert($declaringFunction instanceof ReflectionMethod);
|
||||
return $this->formatType($parameter->getType(), $declaringFunction, $parameter);
|
||||
}
|
||||
private function getParameterDefaultValue(ReflectionParameter $parameter)
|
||||
{
|
||||
if (!$parameter->isDefaultValueAvailable()) {
|
||||
return '';
|
||||
}
|
||||
if (PHP_VERSION_ID < 80100 || is_scalar($parameter->getDefaultValue())) {
|
||||
return ' = ' . var_export($parameter->getDefaultValue(), \true);
|
||||
}
|
||||
$value = rtrim(substr(explode('$' . $parameter->getName() . ' = ', (string) $parameter, 2)[1], 0, -2));
|
||||
if (strpos($value, '\\') !== \false || strpos($value, '::') !== \false) {
|
||||
$value = preg_split("/('(?:[^'\\\\]*+(?:\\\\.)*+)*+')/", $value, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
foreach ($value as $i => $part) {
|
||||
if ($i % 2 === 0) {
|
||||
$value[$i] = preg_replace('/(?<![a-zA-Z0-9_\\x7f-\\xff\\\\])[a-zA-Z0-9_\\x7f-\\xff]++(?:\\\\[a-zA-Z0-9_\\x7f-\\xff]++|::)++/', '\\\\\\0', $part);
|
||||
}
|
||||
}
|
||||
$value = implode('', $value);
|
||||
}
|
||||
return ' = ' . $value;
|
||||
}
|
||||
private function getParameterNamesForInvoke(array $parameters)
|
||||
{
|
||||
return array_map(static function (ReflectionParameter $parameter) {
|
||||
return '$' . $parameter->getName();
|
||||
}, $parameters);
|
||||
}
|
||||
private function getParameterNamesForParentCall(array $parameters)
|
||||
{
|
||||
return array_map(static function (ReflectionParameter $parameter) {
|
||||
$name = '';
|
||||
if ($parameter->isVariadic()) {
|
||||
$name .= '...';
|
||||
}
|
||||
$name .= '$' . $parameter->getName();
|
||||
return $name;
|
||||
}, $parameters);
|
||||
}
|
||||
private function getMethodReturnType(ReflectionMethod $method)
|
||||
{
|
||||
if (!$method->hasReturnType()) {
|
||||
return '';
|
||||
}
|
||||
return ': ' . $this->formatType($method->getReturnType(), $method);
|
||||
}
|
||||
private function shouldProxiedMethodReturn(ReflectionMethod $method)
|
||||
{
|
||||
if (!$method->hasReturnType()) {
|
||||
return \true;
|
||||
}
|
||||
return !in_array(strtolower($this->formatType($method->getReturnType(), $method)), ['void', 'never'], \true);
|
||||
}
|
||||
private function formatType(ReflectionType $type, ReflectionMethod $method, ?ReflectionParameter $parameter = null)
|
||||
{
|
||||
if ($type instanceof ReflectionUnionType) {
|
||||
return implode('|', array_map(function (ReflectionType $unionedType) use($method, $parameter) {
|
||||
if ($unionedType instanceof ReflectionIntersectionType) {
|
||||
return '(' . $this->formatType($unionedType, $method, $parameter) . ')';
|
||||
}
|
||||
return $this->formatType($unionedType, $method, $parameter);
|
||||
}, $type->getTypes()));
|
||||
}
|
||||
if ($type instanceof ReflectionIntersectionType) {
|
||||
return implode('&', array_map(function (ReflectionType $intersectedType) use($method, $parameter) {
|
||||
return $this->formatType($intersectedType, $method, $parameter);
|
||||
}, $type->getTypes()));
|
||||
}
|
||||
assert($type instanceof ReflectionNamedType);
|
||||
$name = $type->getName();
|
||||
$nameLower = strtolower($name);
|
||||
if ($nameLower === 'static') {
|
||||
$name = 'static';
|
||||
}
|
||||
if ($nameLower === 'self') {
|
||||
$name = $method->getDeclaringClass()->getName();
|
||||
}
|
||||
if ($nameLower === 'parent') {
|
||||
$name = $method->getDeclaringClass()->getParentClass()->getName();
|
||||
}
|
||||
if (!$type->isBuiltin() && !class_exists($name) && !interface_exists($name) && $name !== 'static') {
|
||||
if ($parameter !== null) {
|
||||
throw UnexpectedValueException::invalidParameterTypeHint($method->getDeclaringClass()->getName(), $method->getName(), $parameter->getName());
|
||||
}
|
||||
throw UnexpectedValueException::invalidReturnTypeHint($method->getDeclaringClass()->getName(), $method->getName());
|
||||
}
|
||||
if (!$type->isBuiltin() && $name !== 'static') {
|
||||
$name = '\\' . $name;
|
||||
}
|
||||
if ($type->allowsNull() && !in_array($name, ['mixed', 'null'], \true) && ($parameter === null || !$parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== null)) {
|
||||
$name = '?' . $name;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Util;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use MailPoetVendor\Doctrine\Persistence\Proxy;
|
||||
use ReflectionClass;
|
||||
use function get_class;
|
||||
use function get_parent_class;
|
||||
use function ltrim;
|
||||
use function rtrim;
|
||||
use function strrpos;
|
||||
use function substr;
|
||||
class ClassUtils
|
||||
{
|
||||
public static function getRealClass($className)
|
||||
{
|
||||
$pos = strrpos($className, '\\' . Proxy::MARKER . '\\');
|
||||
if ($pos === \false) {
|
||||
return $className;
|
||||
}
|
||||
return substr($className, $pos + Proxy::MARKER_LENGTH + 2);
|
||||
}
|
||||
public static function getClass($object)
|
||||
{
|
||||
return self::getRealClass(get_class($object));
|
||||
}
|
||||
public static function getParentClass($className)
|
||||
{
|
||||
return get_parent_class(self::getRealClass($className));
|
||||
}
|
||||
public static function newReflectionClass($className)
|
||||
{
|
||||
return new ReflectionClass(self::getRealClass($className));
|
||||
}
|
||||
public static function newReflectionObject($object)
|
||||
{
|
||||
return self::newReflectionClass(self::getClass($object));
|
||||
}
|
||||
public static function generateProxyClassName($className, $proxyNamespace)
|
||||
{
|
||||
return rtrim($proxyNamespace, '\\') . '\\' . Proxy::MARKER . '\\' . ltrim($className, '\\');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
namespace MailPoetVendor\Doctrine\Common\Util;
|
||||
if (!defined('ABSPATH')) exit;
|
||||
use ArrayIterator;
|
||||
use ArrayObject;
|
||||
use DateTimeInterface;
|
||||
use MailPoetVendor\Doctrine\Common\Collections\Collection;
|
||||
use MailPoetVendor\Doctrine\Persistence\Proxy;
|
||||
use stdClass;
|
||||
use function array_keys;
|
||||
use function count;
|
||||
use function end;
|
||||
use function explode;
|
||||
use function extension_loaded;
|
||||
use function get_class;
|
||||
use function html_entity_decode;
|
||||
use function ini_get;
|
||||
use function ini_set;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function method_exists;
|
||||
use function ob_end_clean;
|
||||
use function ob_get_contents;
|
||||
use function ob_start;
|
||||
use function spl_object_hash;
|
||||
use function strip_tags;
|
||||
use function var_dump;
|
||||
final class Debug
|
||||
{
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
public static function dump($var, $maxDepth = 2, $stripTags = \true, $echo = \true)
|
||||
{
|
||||
$html = ini_get('html_errors');
|
||||
if ($html !== \true) {
|
||||
ini_set('html_errors', 'on');
|
||||
}
|
||||
if (extension_loaded('xdebug')) {
|
||||
ini_set('xdebug.var_display_max_depth', $maxDepth);
|
||||
}
|
||||
$var = self::export($var, $maxDepth);
|
||||
ob_start();
|
||||
var_dump($var);
|
||||
$dump = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$dumpText = $stripTags ? strip_tags(html_entity_decode($dump)) : $dump;
|
||||
ini_set('html_errors', $html);
|
||||
if ($echo) {
|
||||
echo $dumpText;
|
||||
}
|
||||
return $dumpText;
|
||||
}
|
||||
public static function export($var, $maxDepth)
|
||||
{
|
||||
$return = null;
|
||||
$isObj = is_object($var);
|
||||
if ($var instanceof Collection) {
|
||||
$var = $var->toArray();
|
||||
}
|
||||
if (!$maxDepth) {
|
||||
return is_object($var) ? get_class($var) : (is_array($var) ? 'Array(' . count($var) . ')' : $var);
|
||||
}
|
||||
if (is_array($var)) {
|
||||
$return = [];
|
||||
foreach ($var as $k => $v) {
|
||||
$return[$k] = self::export($v, $maxDepth - 1);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
if (!$isObj) {
|
||||
return $var;
|
||||
}
|
||||
$return = new stdClass();
|
||||
if ($var instanceof DateTimeInterface) {
|
||||
$return->__CLASS__ = get_class($var);
|
||||
$return->date = $var->format('c');
|
||||
$return->timezone = $var->getTimezone()->getName();
|
||||
return $return;
|
||||
}
|
||||
$return->__CLASS__ = ClassUtils::getClass($var);
|
||||
if ($var instanceof Proxy) {
|
||||
$return->__IS_PROXY__ = \true;
|
||||
$return->__PROXY_INITIALIZED__ = $var->__isInitialized();
|
||||
}
|
||||
if ($var instanceof ArrayObject || $var instanceof ArrayIterator) {
|
||||
$return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1);
|
||||
}
|
||||
return self::fillReturnWithClassAttributes($var, $return, $maxDepth);
|
||||
}
|
||||
private static function fillReturnWithClassAttributes($var, stdClass $return, $maxDepth)
|
||||
{
|
||||
$clone = (array) $var;
|
||||
foreach (array_keys($clone) as $key) {
|
||||
$aux = explode("\x00", $key);
|
||||
$name = end($aux);
|
||||
if ($aux[0] === '') {
|
||||
$name .= ':' . ($aux[1] === '*' ? 'protected' : $aux[1] . ':private');
|
||||
}
|
||||
$return->{$name} = self::export($clone[$key], $maxDepth - 1);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
public static function toString($obj)
|
||||
{
|
||||
return method_exists($obj, '__toString') ? (string) $obj : get_class($obj) . '@' . spl_object_hash($obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
Reference in New Issue
Block a user