Augmentation vers version 3.3.0

This commit is contained in:
Gauvain Boiché
2020-03-31 15:31:03 +02:00
parent d926806907
commit a1864c0414
2618 changed files with 406015 additions and 31377 deletions

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Autoloader;
use ProxyManager\FileLocator\FileLocatorInterface;
@@ -52,7 +54,7 @@ class Autoloader implements AutoloaderInterface
/**
* {@inheritDoc}
*/
public function __invoke($className)
public function __invoke(string $className) : bool
{
if (class_exists($className, false) || ! $this->classNameInflector->isProxyClassName($className)) {
return false;
@@ -64,6 +66,8 @@ class Autoloader implements AutoloaderInterface
return false;
}
/* @noinspection PhpIncludeInspection */
/* @noinspection UsingInclusionOnceReturnValueInspection */
return (bool) require_once $file;
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Autoloader;
/**
@@ -33,5 +35,5 @@ interface AutoloaderInterface
*
* @return bool
*/
public function __invoke($className);
public function __invoke(string $className) : bool;
}

View File

@@ -16,12 +16,14 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager;
use ProxyManager\Autoloader\Autoloader;
use ProxyManager\Autoloader\AutoloaderInterface;
use ProxyManager\FileLocator\FileLocator;
use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy;
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
use ProxyManager\GeneratorStrategy\GeneratorStrategyInterface;
use ProxyManager\Inflector\ClassNameInflector;
use ProxyManager\Inflector\ClassNameInflectorInterface;
@@ -82,37 +84,12 @@ class Configuration
*/
protected $classSignatureGenerator;
/**
* @deprecated deprecated since version 0.5
* @codeCoverageIgnore
*/
public function setAutoGenerateProxies()
{
}
/**
* @return bool
*
* @deprecated deprecated since version 0.5
* @codeCoverageIgnore
*/
public function doesAutoGenerateProxies()
{
return true;
}
/**
* @param AutoloaderInterface $proxyAutoloader
*/
public function setProxyAutoloader(AutoloaderInterface $proxyAutoloader)
public function setProxyAutoloader(AutoloaderInterface $proxyAutoloader) : void
{
$this->proxyAutoloader = $proxyAutoloader;
}
/**
* @return AutoloaderInterface
*/
public function getProxyAutoloader()
public function getProxyAutoloader() : AutoloaderInterface
{
return $this->proxyAutoloader
?: $this->proxyAutoloader = new Autoloader(
@@ -121,119 +98,75 @@ class Configuration
);
}
/**
* @param string $proxiesNamespace
*/
public function setProxiesNamespace($proxiesNamespace)
public function setProxiesNamespace(string $proxiesNamespace) : void
{
$this->proxiesNamespace = $proxiesNamespace;
}
/**
* @return string
*/
public function getProxiesNamespace()
public function getProxiesNamespace() : string
{
return $this->proxiesNamespace;
}
/**
* @param string $proxiesTargetDir
*/
public function setProxiesTargetDir($proxiesTargetDir)
public function setProxiesTargetDir(string $proxiesTargetDir) : void
{
$this->proxiesTargetDir = (string) $proxiesTargetDir;
$this->proxiesTargetDir = $proxiesTargetDir;
}
/**
* @return string
*/
public function getProxiesTargetDir()
public function getProxiesTargetDir() : string
{
return $this->proxiesTargetDir ?: $this->proxiesTargetDir = sys_get_temp_dir();
}
/**
* @param GeneratorStrategyInterface $generatorStrategy
*/
public function setGeneratorStrategy(GeneratorStrategyInterface $generatorStrategy)
public function setGeneratorStrategy(GeneratorStrategyInterface $generatorStrategy) : void
{
$this->generatorStrategy = $generatorStrategy;
}
/**
* @return GeneratorStrategyInterface
*/
public function getGeneratorStrategy()
public function getGeneratorStrategy() : GeneratorStrategyInterface
{
return $this->generatorStrategy
?: $this->generatorStrategy = new FileWriterGeneratorStrategy(
new FileLocator($this->getProxiesTargetDir())
);
?: $this->generatorStrategy = new EvaluatingGeneratorStrategy();
}
/**
* @param ClassNameInflectorInterface $classNameInflector
*/
public function setClassNameInflector(ClassNameInflectorInterface $classNameInflector)
public function setClassNameInflector(ClassNameInflectorInterface $classNameInflector) : void
{
$this->classNameInflector = $classNameInflector;
}
/**
* @return ClassNameInflectorInterface
*/
public function getClassNameInflector()
public function getClassNameInflector() : ClassNameInflectorInterface
{
return $this->classNameInflector
?: $this->classNameInflector = new ClassNameInflector($this->getProxiesNamespace());
}
/**
* @param SignatureGeneratorInterface $signatureGenerator
*/
public function setSignatureGenerator(SignatureGeneratorInterface $signatureGenerator)
public function setSignatureGenerator(SignatureGeneratorInterface $signatureGenerator) : void
{
$this->signatureGenerator = $signatureGenerator;
}
/**
* @return SignatureGeneratorInterface
*/
public function getSignatureGenerator()
public function getSignatureGenerator() : SignatureGeneratorInterface
{
return $this->signatureGenerator ?: $this->signatureGenerator = new SignatureGenerator();
}
/**
* @param SignatureCheckerInterface $signatureChecker
*/
public function setSignatureChecker(SignatureCheckerInterface $signatureChecker)
public function setSignatureChecker(SignatureCheckerInterface $signatureChecker) : void
{
$this->signatureChecker = $signatureChecker;
}
/**
* @return SignatureCheckerInterface
*/
public function getSignatureChecker()
public function getSignatureChecker() : SignatureCheckerInterface
{
return $this->signatureChecker
?: $this->signatureChecker = new SignatureChecker($this->getSignatureGenerator());
}
/**
* @param ClassSignatureGeneratorInterface $classSignatureGenerator
*/
public function setClassSignatureGenerator(ClassSignatureGeneratorInterface $classSignatureGenerator)
public function setClassSignatureGenerator(ClassSignatureGeneratorInterface $classSignatureGenerator) : void
{
$this->classSignatureGenerator = $classSignatureGenerator;
}
/**
* @return ClassSignatureGeneratorInterface
*/
public function getClassSignatureGenerator()
public function getClassSignatureGenerator() : ClassSignatureGeneratorInterface
{
return $this->classSignatureGenerator
?: new ClassSignatureGenerator($this->getSignatureGenerator());

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Exception;
use BadMethodCallException;
@@ -30,13 +32,8 @@ class DisabledMethodException extends BadMethodCallException implements Exceptio
{
const NAME = __CLASS__;
/**
* @param string $method
*
* @return self
*/
public static function disabledMethod($method)
public static function disabledMethod(string $method) : self
{
return new self(sprintf('Method "%s" is forcefully disabled', (string) $method));
return new self(sprintf('Method "%s" is forcefully disabled', $method));
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Exception;
/**

View File

@@ -16,11 +16,10 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Exception;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionMethod;
use UnexpectedValueException;
/**
@@ -31,13 +30,7 @@ use UnexpectedValueException;
*/
class FileNotWritableException extends UnexpectedValueException implements ExceptionInterface
{
/**
* @param string $fromPath
* @param string $toPath
*
* @return self
*/
public static function fromInvalidMoveOperation($fromPath, $toPath)
public static function fromInvalidMoveOperation(string $fromPath, string $toPath) : self
{
return new self(sprintf(
'Could not move file "%s" to location "%s": '
@@ -48,19 +41,26 @@ class FileNotWritableException extends UnexpectedValueException implements Excep
}
/**
* @deprecated this method is unused, and will be removed in ProxyManager 3.0.0
*
* @param string $path
*
* @return self
*/
public static function fromNonWritableLocation($path)
public static function fromNonWritableLocation($path) : self
{
$messages = array();
$messages = [];
$destination = realpath($path);
if (($destination = realpath($path)) && ! is_file($destination)) {
if (! $destination) {
$messages[] = 'path does not exist';
}
if ($destination && ! is_file($destination)) {
$messages[] = 'exists and is not a file';
}
if (! is_writable($destination)) {
if ($destination && ! is_writable($destination)) {
$messages[] = 'is not writable';
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Exception;
use InvalidArgumentException;
@@ -30,32 +32,17 @@ use ReflectionMethod;
*/
class InvalidProxiedClassException extends InvalidArgumentException implements ExceptionInterface
{
/**
* @param ReflectionClass $reflection
*
* @return self
*/
public static function interfaceNotSupported(ReflectionClass $reflection)
public static function interfaceNotSupported(ReflectionClass $reflection) : self
{
return new self(sprintf('Provided interface "%s" cannot be proxied', $reflection->getName()));
}
/**
* @param ReflectionClass $reflection
*
* @return self
*/
public static function finalClassNotSupported(ReflectionClass $reflection)
public static function finalClassNotSupported(ReflectionClass $reflection) : self
{
return new self(sprintf('Provided class "%s" is final and cannot be proxied', $reflection->getName()));
}
/**
* @param ReflectionClass $reflection
*
* @return self
*/
public static function abstractProtectedMethodsNotSupported(ReflectionClass $reflection)
public static function abstractProtectedMethodsNotSupported(ReflectionClass $reflection) : self
{
return new self(sprintf(
'Provided class "%s" has following protected abstract methods, and therefore cannot be proxied:' . "\n%s",
@@ -63,12 +50,12 @@ class InvalidProxiedClassException extends InvalidArgumentException implements E
implode(
"\n",
array_map(
function (ReflectionMethod $reflectionMethod) {
function (ReflectionMethod $reflectionMethod) : string {
return $reflectionMethod->getDeclaringClass()->getName() . '::' . $reflectionMethod->getName();
},
array_filter(
$reflection->getMethods(),
function (ReflectionMethod $method) {
function (ReflectionMethod $method) : bool {
return $method->isAbstract() && $method->isProtected();
}
)

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Exception;
use InvalidArgumentException;
@@ -28,13 +30,8 @@ use InvalidArgumentException;
*/
class InvalidProxyDirectoryException extends InvalidArgumentException implements ExceptionInterface
{
/**
* @param string $directory
*
* @return self
*/
public static function proxyDirectoryNotFound($directory)
public static function proxyDirectoryNotFound(string $directory) : self
{
return new self(sprintf('Provided directory "%s" does not exist', (string) $directory));
return new self(sprintf('Provided directory "%s" does not exist', $directory));
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Exception;
use LogicException;
@@ -29,12 +31,7 @@ use ReflectionProperty;
*/
class UnsupportedProxiedClassException extends LogicException implements ExceptionInterface
{
/**
* @param ReflectionProperty $property
*
* @return self
*/
public static function unsupportedLocalizedReflectionProperty(ReflectionProperty $property)
public static function unsupportedLocalizedReflectionProperty(ReflectionProperty $property) : self
{
return new self(
sprintf(

View File

@@ -16,10 +16,15 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory;
use ProxyManager\Configuration;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
use ProxyManager\Signature\Exception\InvalidSignatureException;
use ProxyManager\Signature\Exception\MissingSignatureException;
use ProxyManager\Version;
use ReflectionClass;
@@ -41,7 +46,7 @@ abstract class AbstractBaseFactory
*
* @var string[]
*/
private $checkedClasses = array();
private $checkedClasses = [];
/**
* @param \ProxyManager\Configuration $configuration
@@ -53,27 +58,39 @@ abstract class AbstractBaseFactory
/**
* Generate a proxy from a class name
* @param string $className
*
* @param string $className
* @param mixed[] $proxyOptions
*
* @return string proxy class name
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws \OutOfBoundsException
*/
protected function generateProxy($className)
protected function generateProxy(string $className, array $proxyOptions = []) : string
{
if (isset($this->checkedClasses[$className])) {
if (\array_key_exists($className, $this->checkedClasses)) {
return $this->checkedClasses[$className];
}
$proxyParameters = array(
$proxyParameters = [
'className' => $className,
'factory' => get_class($this),
'proxyManagerVersion' => Version::VERSION
);
'proxyManagerVersion' => Version::getVersion(),
];
$proxyClassName = $this
->configuration
->getClassNameInflector()
->getProxyClassName($className, $proxyParameters);
if (! class_exists($proxyClassName)) {
$this->generateProxyClass($proxyClassName, $className, $proxyParameters);
$this->generateProxyClass(
$proxyClassName,
$className,
$proxyParameters,
$proxyOptions
);
}
$this
@@ -84,29 +101,33 @@ abstract class AbstractBaseFactory
return $this->checkedClasses[$className] = $proxyClassName;
}
/**
* @return \ProxyManager\ProxyGenerator\ProxyGeneratorInterface
*/
abstract protected function getGenerator();
abstract protected function getGenerator() : ProxyGeneratorInterface;
/**
* Generates the provided `$proxyClassName` from the given `$className` and `$proxyParameters`
* @param string $proxyClassName
* @param string $className
* @param array $proxyParameters
*
* @return void
* @param string $proxyClassName
* @param string $className
* @param array $proxyParameters
* @param mixed[] $proxyOptions
*/
private function generateProxyClass($proxyClassName, $className, array $proxyParameters)
{
private function generateProxyClass(
string $proxyClassName,
string $className,
array $proxyParameters,
array $proxyOptions = []
) : void {
$className = $this->configuration->getClassNameInflector()->getUserClassName($className);
$phpClass = new ClassGenerator($proxyClassName);
$this->getGenerator()->generate(new ReflectionClass($className), $phpClass);
$this->getGenerator()->generate(new ReflectionClass($className), $phpClass, $proxyOptions);
$phpClass = $this->configuration->getClassSignatureGenerator()->addSignature($phpClass, $proxyParameters);
$this->configuration->getGeneratorStrategy()->generate($phpClass);
$this->configuration->getProxyAutoloader()->__invoke($proxyClassName);
$this->configuration->getGeneratorStrategy()->generate($phpClass, $proxyOptions);
$autoloader = $this->configuration->getProxyAutoloader();
$autoloader($proxyClassName);
}
}

View File

@@ -16,9 +16,15 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory;
use ProxyManager\Proxy\AccessInterceptorInterface;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizerGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
use ProxyManager\Signature\Exception\InvalidSignatureException;
use ProxyManager\Signature\Exception\MissingSignatureException;
/**
* Factory responsible of producing proxy objects
@@ -40,19 +46,26 @@ class AccessInterceptorScopeLocalizerFactory extends AbstractBaseFactory
* @param \Closure[] $suffixInterceptors an array (indexed by method name) of interceptor closures to be called
* after method logic is executed
*
* @return \ProxyManager\Proxy\AccessInterceptorInterface
* @return AccessInterceptorInterface
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws \OutOfBoundsException
*/
public function createProxy($instance, array $prefixInterceptors = array(), array $suffixInterceptors = array())
{
public function createProxy(
$instance,
array $prefixInterceptors = [],
array $suffixInterceptors = []
) : AccessInterceptorInterface {
$proxyClassName = $this->generateProxy(get_class($instance));
return new $proxyClassName($instance, $prefixInterceptors, $suffixInterceptors);
return $proxyClassName::staticProxyConstructor($instance, $prefixInterceptors, $suffixInterceptors);
}
/**
* {@inheritDoc}
*/
protected function getGenerator()
protected function getGenerator() : ProxyGeneratorInterface
{
return $this->generator ?: $this->generator = new AccessInterceptorScopeLocalizerGenerator();
}

View File

@@ -16,9 +16,15 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory;
use ProxyManager\Proxy\AccessInterceptorValueHolderInterface;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolderGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
use ProxyManager\Signature\Exception\InvalidSignatureException;
use ProxyManager\Signature\Exception\MissingSignatureException;
/**
* Factory responsible of producing proxy objects
@@ -40,19 +46,26 @@ class AccessInterceptorValueHolderFactory extends AbstractBaseFactory
* @param \Closure[] $suffixInterceptors an array (indexed by method name) of interceptor closures to be called
* after method logic is executed
*
* @return \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface
* @return AccessInterceptorValueHolderInterface
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws \OutOfBoundsException
*/
public function createProxy($instance, array $prefixInterceptors = array(), array $suffixInterceptors = array())
{
public function createProxy(
$instance,
array $prefixInterceptors = [],
array $suffixInterceptors = []
) : AccessInterceptorValueHolderInterface {
$proxyClassName = $this->generateProxy(get_class($instance));
return new $proxyClassName($instance, $prefixInterceptors, $suffixInterceptors);
return $proxyClassName::staticProxyConstructor($instance, $prefixInterceptors, $suffixInterceptors);
}
/**
* {@inheritDoc}
*/
protected function getGenerator()
protected function getGenerator() : ProxyGeneratorInterface
{
return $this->generator ?: $this->generator = new AccessInterceptorValueHolderGenerator();
}

View File

@@ -16,19 +16,24 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory;
use Closure;
use ProxyManager\Proxy\GhostObjectInterface;
use ProxyManager\ProxyGenerator\LazyLoadingGhostGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
use ProxyManager\Signature\Exception\InvalidSignatureException;
use ProxyManager\Signature\Exception\MissingSignatureException;
/**
* Factory responsible of producing ghost instances
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*
* @method \ProxyManager\Proxy\GhostObjectInterface createProxy($className, \Closure $initializer)
*/
class LazyLoadingGhostFactory extends AbstractLazyFactory
class LazyLoadingGhostFactory extends AbstractBaseFactory
{
/**
* @var \ProxyManager\ProxyGenerator\LazyLoadingGhostGenerator|null
@@ -38,8 +43,60 @@ class LazyLoadingGhostFactory extends AbstractLazyFactory
/**
* {@inheritDoc}
*/
protected function getGenerator()
protected function getGenerator() : ProxyGeneratorInterface
{
return $this->generator ?: $this->generator = new LazyLoadingGhostGenerator();
}
/**
* Creates a new lazy proxy instance of the given class with
* the given initializer
*
* Please refer to the following documentation when using this method:
*
* @link https://github.com/Ocramius/ProxyManager/blob/master/docs/lazy-loading-ghost-object.md
*
* @param string $className name of the class to be proxied
* @param Closure $initializer initializer to be passed to the proxy. The initializer closure should have following
* signature:
*
* <code>
* $initializer = function (
* GhostObjectInterface $proxy,
* string $method,
* array $parameters,
* & $initializer,
* array $properties
* ) {};
* </code>
*
* Where:
* - $proxy is the proxy instance on which the initializer is acting
* - $method is the name of the method that triggered the lazy initialization
* - $parameters are the parameters that were passed to $method
* - $initializer by-ref initializer - should be assigned null in the initializer body
* - $properties a by-ref map of the properties of the object, indexed by PHP
* internal property name. Assign values to it to initialize the
* object state
*
* @param mixed[] $proxyOptions a set of options to be used when generating the proxy. Currently supports only
* key "skippedProperties", which allows to skip lazy-loading of some properties.
* "skippedProperties" is a string[], containing a list of properties referenced
* via PHP's internal property name (i.e. "\0ClassName\0propertyName")
*
* @return GhostObjectInterface
*
* @throws MissingSignatureException
* @throws InvalidSignatureException
* @throws \OutOfBoundsException
*/
public function createProxy(
string $className,
Closure $initializer,
array $proxyOptions = []
) : GhostObjectInterface {
$proxyClassName = $this->generateProxy($className, $proxyOptions);
return $proxyClassName::staticProxyConstructor($initializer);
}
}

View File

@@ -16,29 +16,41 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory;
use ProxyManager\Proxy\VirtualProxyInterface;
use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
/**
* Factory responsible of producing virtual proxy instances
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*
* @method \ProxyManager\Proxy\VirtualProxyInterface createProxy($className, \Closure $initializer)
*/
class LazyLoadingValueHolderFactory extends AbstractLazyFactory
class LazyLoadingValueHolderFactory extends AbstractBaseFactory
{
/**
* @var \ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator|null
*/
private $generator;
public function createProxy(
string $className,
\Closure $initializer,
array $proxyOptions = []
) : VirtualProxyInterface {
$proxyClassName = $this->generateProxy($className, $proxyOptions);
return $proxyClassName::staticProxyConstructor($initializer);
}
/**
* {@inheritDoc}
*/
protected function getGenerator()
protected function getGenerator() : ProxyGeneratorInterface
{
return $this->generator ?: $this->generator = new LazyLoadingValueHolderGenerator();
}

View File

@@ -16,9 +16,15 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory;
use ProxyManager\Proxy\NullObjectInterface;
use ProxyManager\ProxyGenerator\NullObjectGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
use ProxyManager\Signature\Exception\InvalidSignatureException;
use ProxyManager\Signature\Exception\MissingSignatureException;
/**
* Factory responsible of producing proxy objects
@@ -36,20 +42,24 @@ class NullObjectFactory extends AbstractBaseFactory
/**
* @param object $instanceOrClassName the object to be wrapped or interface to transform to null object
*
* @return \ProxyManager\Proxy\NullobjectInterface
* @return NullObjectInterface
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws \OutOfBoundsException
*/
public function createProxy($instanceOrClassName)
public function createProxy($instanceOrClassName) : NullObjectInterface
{
$className = is_object($instanceOrClassName) ? get_class($instanceOrClassName) : $instanceOrClassName;
$proxyClassName = $this->generateProxy($className);
return new $proxyClassName();
return $proxyClassName::staticProxyConstructor();
}
/**
* {@inheritDoc}
*/
protected function getGenerator()
protected function getGenerator() : ProxyGeneratorInterface
{
return $this->generator ?: $this->generator = new NullObjectGenerator();
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory\RemoteObject\Adapter;
use ProxyManager\Factory\RemoteObject\AdapterInterface;
@@ -41,7 +43,7 @@ abstract class BaseAdapter implements AdapterInterface
*
* @var string[]
*/
protected $map = array();
protected $map = [];
/**
* Constructor
@@ -49,7 +51,7 @@ abstract class BaseAdapter implements AdapterInterface
* @param Client $client
* @param array $map map of service names to their aliases
*/
public function __construct(Client $client, array $map = array())
public function __construct(Client $client, array $map = [])
{
$this->client = $client;
$this->map = $map;
@@ -58,11 +60,11 @@ abstract class BaseAdapter implements AdapterInterface
/**
* {@inheritDoc}
*/
public function call($wrappedClass, $method, array $params = array())
public function call(string $wrappedClass, string $method, array $params = [])
{
$serviceName = $this->getServiceName($wrappedClass, $method);
if (isset($this->map[$serviceName])) {
if (\array_key_exists($serviceName, $this->map)) {
$serviceName = $this->map[$serviceName];
}
@@ -77,5 +79,5 @@ abstract class BaseAdapter implements AdapterInterface
*
* @return string Service name
*/
abstract protected function getServiceName($wrappedClass, $method);
abstract protected function getServiceName(string $wrappedClass, string $method) : string;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory\RemoteObject\Adapter;
/**
@@ -29,7 +31,7 @@ class JsonRpc extends BaseAdapter
/**
* {@inheritDoc}
*/
protected function getServiceName($wrappedClass, $method)
protected function getServiceName(string $wrappedClass, string $method) : string
{
return $wrappedClass . '.' . $method;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory\RemoteObject\Adapter;
/**
@@ -29,8 +31,8 @@ class Soap extends BaseAdapter
/**
* {@inheritDoc}
*/
protected function getServiceName($wrappedClass, $method)
protected function getServiceName(string $wrappedClass, string $method) : string
{
return (string) $method;
return $method;
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory\RemoteObject\Adapter;
/**
@@ -29,7 +31,7 @@ class XmlRpc extends BaseAdapter
/**
* {@inheritDoc}
*/
protected function getServiceName($wrappedClass, $method)
protected function getServiceName(string $wrappedClass, string $method) : string
{
return $wrappedClass . '.' . $method;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory\RemoteObject;
/**
@@ -33,5 +35,5 @@ interface AdapterInterface
* @param string $method
* @param array $params
*/
public function call($wrappedClass, $method, array $params = array());
public function call(string $wrappedClass, string $method, array $params = []);
}

View File

@@ -16,11 +16,17 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Factory;
use ProxyManager\Configuration;
use ProxyManager\Factory\RemoteObject\AdapterInterface;
use ProxyManager\Proxy\RemoteObjectInterface;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
use ProxyManager\ProxyGenerator\RemoteObjectGenerator;
use ProxyManager\Signature\Exception\InvalidSignatureException;
use ProxyManager\Signature\Exception\MissingSignatureException;
/**
* Factory responsible of producing remote proxy objects
@@ -56,20 +62,25 @@ class RemoteObjectFactory extends AbstractBaseFactory
/**
* @param string|object $instanceOrClassName
*
* @return \ProxyManager\Proxy\RemoteObjectInterface
* @return RemoteObjectInterface
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws \OutOfBoundsException
*/
public function createProxy($instanceOrClassName)
public function createProxy($instanceOrClassName) : RemoteObjectInterface
{
$className = is_object($instanceOrClassName) ? get_class($instanceOrClassName) : $instanceOrClassName;
$proxyClassName = $this->generateProxy($className);
$proxyClassName = $this->generateProxy(
is_object($instanceOrClassName) ? get_class($instanceOrClassName) : $instanceOrClassName
);
return new $proxyClassName($this->adapter);
return $proxyClassName::staticProxyConstructor($this->adapter);
}
/**
* {@inheritDoc}
*/
protected function getGenerator()
protected function getGenerator() : ProxyGeneratorInterface
{
return $this->generator ?: $this->generator = new RemoteObjectGenerator();
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\FileLocator;
use ProxyManager\Exception\InvalidProxyDirectoryException;
@@ -38,19 +40,21 @@ class FileLocator implements FileLocatorInterface
*
* @throws \ProxyManager\Exception\InvalidProxyDirectoryException
*/
public function __construct($proxiesDirectory)
public function __construct(string $proxiesDirectory)
{
$this->proxiesDirectory = realpath($proxiesDirectory);
$absolutePath = realpath($proxiesDirectory);
if (false === $this->proxiesDirectory) {
if (false === $absolutePath) {
throw InvalidProxyDirectoryException::proxyDirectoryNotFound($proxiesDirectory);
}
$this->proxiesDirectory = $absolutePath;
}
/**
* {@inheritDoc}
*/
public function getProxyFileName($className)
public function getProxyFileName(string $className) : string
{
return $this->proxiesDirectory . DIRECTORY_SEPARATOR . str_replace('\\', '', $className) . '.php';
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\FileLocator;
/**
@@ -33,5 +35,5 @@ interface FileLocatorInterface
*
* @return string
*/
public function getProxyFileName($className);
public function getProxyFileName(string $className) : string;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Generator;
use Zend\Code\Generator\ClassGenerator as ZendClassGenerator;
@@ -31,7 +33,7 @@ class ClassGenerator extends ZendClassGenerator
/**
* {@inheritDoc}
*/
public function setExtendedClass($extendedClass)
public function setExtendedClass($extendedClass) : parent
{
if ($extendedClass) {
$extendedClass = '\\' . trim($extendedClass, '\\');
@@ -43,7 +45,7 @@ class ClassGenerator extends ZendClassGenerator
/**
* {@inheritDoc}
*/
public function setImplementedInterfaces(array $interfaces)
public function setImplementedInterfaces(array $interfaces) : parent
{
foreach ($interfaces as & $interface) {
$interface = '\\' . trim($interface, '\\');

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Generator;
use ReflectionClass;
@@ -33,7 +35,7 @@ class MagicMethodGenerator extends MethodGenerator
* @param string $name
* @param array $parameters
*/
public function __construct(ReflectionClass $originalClass, $name, array $parameters = array())
public function __construct(ReflectionClass $originalClass, string $name, array $parameters = [])
{
parent::__construct(
$name,

View File

@@ -16,9 +16,10 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Generator;
use Zend\Code\Generator\DocBlockGenerator;
use Zend\Code\Generator\MethodGenerator as ZendMethodGenerator;
use Zend\Code\Reflection\MethodReflection;
@@ -31,131 +32,15 @@ use Zend\Code\Reflection\MethodReflection;
class MethodGenerator extends ZendMethodGenerator
{
/**
* @var bool
*/
protected $returnsReference = false;
/**
* @param boolean $returnsReference
*/
public function setReturnsReference($returnsReference)
{
$this->returnsReference = (bool) $returnsReference;
}
/**
* @return boolean
*/
public function returnsReference()
{
return $this->returnsReference;
}
/**
* @override enforces generation of \ProxyManager\Generator\MethodGenerator
*
* {@inheritDoc}
*/
public static function fromReflection(MethodReflection $reflectionMethod)
public static function fromReflection(MethodReflection $reflectionMethod) : self
{
/* @var $method self */
$method = new static();
$method = parent::fromReflection($reflectionMethod);
$method->setSourceContent($reflectionMethod->getContents(false));
$method->setSourceDirty(false);
if ($reflectionMethod->getDocComment() != '') {
$method->setDocBlock(DocBlockGenerator::fromReflection($reflectionMethod->getDocBlock()));
}
$method->setFinal($reflectionMethod->isFinal());
$method->setVisibility(self::extractVisibility($reflectionMethod));
foreach ($reflectionMethod->getParameters() as $reflectionParameter) {
$method->setParameter(ParameterGenerator::fromReflection($reflectionParameter));
}
$method->setStatic($reflectionMethod->isStatic());
$method->setName($reflectionMethod->getName());
$method->setBody($reflectionMethod->getBody());
$method->setReturnsReference($reflectionMethod->returnsReference());
$method->setInterface(false);
return $method;
}
/**
* Retrieves the visibility for the given method reflection
*
* @param MethodReflection $reflectionMethod
*
* @return string
*/
private static function extractVisibility(MethodReflection $reflectionMethod)
{
if ($reflectionMethod->isPrivate()) {
return static::VISIBILITY_PRIVATE;
}
if ($reflectionMethod->isProtected()) {
return static::VISIBILITY_PROTECTED;
}
return static::VISIBILITY_PUBLIC;
}
/**
* @override fixes by-reference return value in zf2's method generator
*
* {@inheritDoc}
*/
public function generate()
{
$output = '';
$indent = $this->getIndentation();
if (null !== ($docBlock = $this->getDocBlock())) {
$docBlock->setIndentation($indent);
$output .= $docBlock->generate();
}
$output .= $indent . $this->generateMethodDeclaration() . self::LINE_FEED . $indent . '{' . self::LINE_FEED;
if ($this->body) {
$output .= preg_replace('#^(.+?)$#m', $indent . $indent . '$1', trim($this->body))
. self::LINE_FEED;
}
$output .= $indent . '}' . self::LINE_FEED;
return $output;
}
/**
* @return string
*/
private function generateMethodDeclaration()
{
$output = $this->generateVisibility()
. ' function '
. (($this->returnsReference()) ? '& ' : '')
. $this->getName() . '(';
$parameterOutput = array();
foreach ($this->getParameters() as $parameter) {
$parameterOutput[] = $parameter->generate();
}
return $output . implode(', ', $parameterOutput) . ')';
}
/**
* @return string
*/
private function generateVisibility()
{
return $this->isAbstract() ? 'abstract ' : (($this->isFinal()) ? 'final ' : '')
. ($this->getVisibility() . (($this->isStatic()) ? ' static' : ''));
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Generator\Util;
use ReflectionClass;
@@ -30,18 +32,11 @@ use Zend\Code\Generator\MethodGenerator;
*/
final class ClassGeneratorUtils
{
/**
* @param ReflectionClass $originalClass
* @param ClassGenerator $classGenerator
* @param MethodGenerator $generatedMethod
*
* @return void|false
*/
public static function addMethodIfNotFinal(
ReflectionClass $originalClass,
ClassGenerator $classGenerator,
MethodGenerator $generatedMethod
) {
) : bool {
$methodName = $generatedMethod->getName();
if ($originalClass->hasMethod($methodName) && $originalClass->getMethod($methodName)->isFinal()) {
@@ -49,5 +44,7 @@ final class ClassGeneratorUtils
}
$classGenerator->addMethodFromGenerator($generatedMethod);
return true;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Generator\Util;
/**
* Utility class to generate return expressions in method, given a method signature.
*
* This is required since return expressions may be forbidden by the method signature (void).
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*/
final class ProxiedMethodReturnExpression
{
public static function generate(string $returnedValueExpression, ?\ReflectionMethod $originalMethod) : string
{
if ($originalMethod && 'void' === (string) $originalMethod->getReturnType()) {
return $returnedValueExpression . ";\nreturn;";
}
return 'return ' . $returnedValueExpression . ';';
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Generator\Util;
/**
@@ -37,7 +39,7 @@ abstract class UniqueIdentifierGenerator
*
* @return string
*/
public static function getIdentifier($name)
public static function getIdentifier(string $name) : string
{
return str_replace(
'.',

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\GeneratorStrategy;
use Zend\Code\Generator\ClassGenerator;
@@ -31,7 +33,7 @@ class BaseGeneratorStrategy implements GeneratorStrategyInterface
/**
* {@inheritDoc}
*/
public function generate(ClassGenerator $classGenerator)
public function generate(ClassGenerator $classGenerator) : string
{
return $classGenerator->generate();
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\GeneratorStrategy;
use Zend\Code\Generator\ClassGenerator;
@@ -38,7 +40,9 @@ class EvaluatingGeneratorStrategy implements GeneratorStrategyInterface
*/
public function __construct()
{
// @codeCoverageIgnoreStart
$this->canEval = ! ini_get('suhosin.executor.disable_eval');
// @codeCoverageIgnoreEnd
}
/**
@@ -46,21 +50,22 @@ class EvaluatingGeneratorStrategy implements GeneratorStrategyInterface
*
* {@inheritDoc}
*/
public function generate(ClassGenerator $classGenerator)
public function generate(ClassGenerator $classGenerator) : string
{
$code = $classGenerator->generate();
// @codeCoverageIgnoreStart
if (! $this->canEval) {
// @codeCoverageIgnoreStart
$fileName = sys_get_temp_dir() . '/EvaluatingGeneratorStrategy.php.tmp.' . uniqid('', true);
$fileName = tempnam(sys_get_temp_dir(), 'EvaluatingGeneratorStrategy.php.tmp.');
file_put_contents($fileName, "<?php\n" . $code);
/* @noinspection PhpIncludeInspection */
require $fileName;
unlink($fileName);
return $code;
// @codeCoverageIgnoreEnd
}
// @codeCoverageIgnoreEnd
eval($code);

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\GeneratorStrategy;
use ProxyManager\Exception\FileNotWritableException;
@@ -56,8 +58,10 @@ class FileWriterGeneratorStrategy implements GeneratorStrategyInterface
* Write generated code to disk and return the class code
*
* {@inheritDoc}
*
* @throws FileNotWritableException
*/
public function generate(ClassGenerator $classGenerator)
public function generate(ClassGenerator $classGenerator) : string
{
$className = trim($classGenerator->getNamespaceName(), '\\')
. '\\' . trim($classGenerator->getName(), '\\');
@@ -68,15 +72,11 @@ class FileWriterGeneratorStrategy implements GeneratorStrategyInterface
try {
$this->writeFile("<?php\n\n" . $generatedCode, $fileName);
} catch (FileNotWritableException $fileNotWritable) {
return $generatedCode;
} finally {
restore_error_handler();
throw $fileNotWritable;
}
restore_error_handler();
return $generatedCode;
}
/**
@@ -88,13 +88,11 @@ class FileWriterGeneratorStrategy implements GeneratorStrategyInterface
*
* @throws FileNotWritableException
*/
private function writeFile($source, $location)
private function writeFile(string $source, string $location) : void
{
$tmpFileName = $location . '.' . uniqid('', true);
$tmpFileName = tempnam($location, 'temporaryProxyManagerFile');
if (! file_put_contents($tmpFileName, $source)) {
throw FileNotWritableException::fromNonWritableLocation($tmpFileName);
}
file_put_contents($tmpFileName, $source);
if (! rename($tmpFileName, $location)) {
unlink($tmpFileName);

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\GeneratorStrategy;
use Zend\Code\Generator\ClassGenerator;
@@ -35,5 +37,5 @@ interface GeneratorStrategyInterface
*
* @return string the class body
*/
public function generate(ClassGenerator $classGenerator);
public function generate(ClassGenerator $classGenerator) : string;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Inflector;
use ProxyManager\Inflector\Util\ParameterHasher;
@@ -51,9 +53,9 @@ final class ClassNameInflector implements ClassNameInflectorInterface
/**
* @param string $proxyNamespace
*/
public function __construct($proxyNamespace)
public function __construct(string $proxyNamespace)
{
$this->proxyNamespace = (string) $proxyNamespace;
$this->proxyNamespace = $proxyNamespace;
$this->proxyMarker = '\\' . static::PROXY_MARKER . '\\';
$this->proxyMarkerLength = strlen($this->proxyMarker);
$this->parameterHasher = new ParameterHasher();
@@ -62,7 +64,7 @@ final class ClassNameInflector implements ClassNameInflectorInterface
/**
* {@inheritDoc}
*/
public function getUserClassName($className)
public function getUserClassName(string $className) : string
{
$className = ltrim($className, '\\');
@@ -80,7 +82,7 @@ final class ClassNameInflector implements ClassNameInflectorInterface
/**
* {@inheritDoc}
*/
public function getProxyClassName($className, array $options = array())
public function getProxyClassName(string $className, array $options = []) : string
{
return $this->proxyNamespace
. $this->proxyMarker
@@ -91,7 +93,7 @@ final class ClassNameInflector implements ClassNameInflectorInterface
/**
* {@inheritDoc}
*/
public function isProxyClassName($className)
public function isProxyClassName(string $className) : bool
{
return false !== strrpos($className, $this->proxyMarker);
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Inflector;
/**
@@ -38,7 +40,7 @@ interface ClassNameInflectorInterface
*
* @return string
*/
public function getUserClassName($className);
public function getUserClassName(string $className) : string;
/**
* Retrieve the class name of the proxy for the given user-defined class name
@@ -48,7 +50,7 @@ interface ClassNameInflectorInterface
*
* @return string
*/
public function getProxyClassName($className, array $options = array());
public function getProxyClassName(string $className, array $options = []) : string;
/**
* Retrieve whether the provided class name is a proxy
@@ -57,5 +59,5 @@ interface ClassNameInflectorInterface
*
* @return bool
*/
public function isProxyClassName($className);
public function isProxyClassName(string $className) : bool;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Inflector\Util;
/**
@@ -34,7 +36,7 @@ class ParameterEncoder
*
* @return string
*/
public function encodeParameters(array $parameters)
public function encodeParameters(array $parameters) : string
{
return base64_encode(serialize($parameters));
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Inflector\Util;
/**
@@ -33,7 +35,7 @@ class ParameterHasher
*
* @return string
*/
public function hashParameters(array $parameters)
public function hashParameters(array $parameters) : string
{
return md5(serialize($parameters));
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**
@@ -34,7 +36,7 @@ interface AccessInterceptorInterface extends ProxyInterface
* A prefix interceptor should have a signature like following:
*
* <code>
* $prefixInterceptor = function ($proxy, $instance, $method, $params, & $returnEarly) {};
* $interceptor = function ($proxy, $instance, string $method, array $params, & $returnEarly) {};
* </code>
*
* @param string $methodName name of the intercepted method
@@ -42,7 +44,7 @@ interface AccessInterceptorInterface extends ProxyInterface
*
* @return void
*/
public function setMethodPrefixInterceptor($methodName, \Closure $prefixInterceptor = null);
public function setMethodPrefixInterceptor(string $methodName, \Closure $prefixInterceptor = null);
/**
* Set or remove the suffix interceptor for a method
@@ -52,7 +54,7 @@ interface AccessInterceptorInterface extends ProxyInterface
* A prefix interceptor should have a signature like following:
*
* <code>
* $suffixInterceptor = function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) {};
* $interceptor = function ($proxy, $instance, string $method, array $params, $returnValue, & $returnEarly) {};
* </code>
*
* @param string $methodName name of the intercepted method
@@ -60,5 +62,5 @@ interface AccessInterceptorInterface extends ProxyInterface
*
* @return void
*/
public function setMethodSuffixInterceptor($methodName, \Closure $suffixInterceptor = null);
public function setMethodSuffixInterceptor(string $methodName, \Closure $suffixInterceptor = null);
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**
* Aggregates AccessInterceptor and ValueHolderInterface, mostly for return type hinting
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*/
interface AccessInterceptorValueHolderInterface extends AccessInterceptorInterface, ValueHolderInterface
{
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy\Exception;
use RuntimeException;

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**
@@ -34,7 +36,7 @@ interface LazyLoadingInterface extends ProxyInterface
* An initializer should have a signature like following:
*
* <code>
* $initializer = function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) {};
* $initializer = function (& $wrappedObject, $proxy, string $method, array $parameters, & $initializer) {};
* </code>
*
* @param \Closure|null $initializer
@@ -53,12 +55,12 @@ interface LazyLoadingInterface extends ProxyInterface
*
* @return bool true if the proxy could be initialized
*/
public function initializeProxy();
public function initializeProxy() : bool;
/**
* Retrieves current initialization status of the proxy
*
* @return bool
*/
public function isProxyInitialized();
public function isProxyInitialized() : bool;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\Proxy;
/**

View File

@@ -16,11 +16,14 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManager\ProxyGenerator\Util\UnsetPropertiesGenerator;
use ReflectionClass;
use ReflectionProperty;
/**
* Magic `__wakeup` for lazy loading value holder objects
@@ -32,19 +35,16 @@ class MagicWakeup extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
*/
public function __construct(ReflectionClass $originalClass)
{
parent::__construct($originalClass, '__wakeup');
/* @var $publicProperties \ReflectionProperty[] */
$publicProperties = $originalClass->getProperties(ReflectionProperty::IS_PUBLIC);
$unsetProperties = array();
foreach ($publicProperties as $publicProperty) {
$unsetProperties[] = '$this->' . $publicProperty->getName();
}
$this->setBody($unsetProperties ? 'unset(' . implode(', ', $unsetProperties) . ");" : '');
$this->setBody(UnsetPropertiesGenerator::generateSnippet(
Properties::fromReflectionClass($originalClass),
'this'
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator;
use Closure;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use Zend\Code\Generator\PropertyGenerator;
/**
@@ -33,6 +36,10 @@ class SetMethodPrefixInterceptor extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $prefixInterceptor
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $prefixInterceptor)
{
@@ -40,11 +47,11 @@ class SetMethodPrefixInterceptor extends MethodGenerator
$interceptor = new ParameterGenerator('prefixInterceptor');
$interceptor->setType('Closure');
$interceptor->setType(Closure::class);
$interceptor->setDefaultValue(null);
$this->setParameter(new ParameterGenerator('methodName'));
$this->setParameter(new ParameterGenerator('methodName', 'string'));
$this->setParameter($interceptor);
$this->setDocblock('{@inheritDoc}');
$this->setDocBlock('{@inheritDoc}');
$this->setBody('$this->' . $prefixInterceptor->getName() . '[$methodName] = $prefixInterceptor;');
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator;
use Closure;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use Zend\Code\Generator\PropertyGenerator;
/**
@@ -33,6 +36,10 @@ class SetMethodSuffixInterceptor extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $suffixInterceptor
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $suffixInterceptor)
{
@@ -40,11 +47,11 @@ class SetMethodSuffixInterceptor extends MethodGenerator
$interceptor = new ParameterGenerator('suffixInterceptor');
$interceptor->setType('Closure');
$interceptor->setType(Closure::class);
$interceptor->setDefaultValue(null);
$this->setParameter(new ParameterGenerator('methodName'));
$this->setParameter(new ParameterGenerator('methodName', 'string'));
$this->setParameter($interceptor);
$this->setDocblock('{@inheritDoc}');
$this->setDocBlock('{@inheritDoc}');
$this->setBody('$this->' . $suffixInterceptor->getName() . '[$methodName] = $suffixInterceptor;');
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptor\PropertyGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
@@ -31,13 +33,15 @@ class MethodPrefixInterceptors extends PropertyGenerator
{
/**
* Constructor
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct()
{
parent::__construct(UniqueIdentifierGenerator::getIdentifier('methodPrefixInterceptors'));
$this->setDefaultValue(array());
$this->setDefaultValue([]);
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocblock('@var \\Closure[] map of interceptors to be called per-method before execution');
$this->setDocBlock('@var \\Closure[] map of interceptors to be called per-method before execution');
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptor\PropertyGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
@@ -31,13 +33,15 @@ class MethodSuffixInterceptors extends PropertyGenerator
{
/**
* Constructor
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct()
{
parent::__construct(UniqueIdentifierGenerator::getIdentifier('methodSuffixInterceptors'));
$this->setDefaultValue(array());
$this->setDefaultValue([]);
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocblock('@var \\Closure[] map of interceptors to be called per-method after execution');
$this->setDocBlock('@var \\Closure[] map of interceptors to be called per-method after execution');
}
}

View File

@@ -0,0 +1,89 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionClass;
use Zend\Code\Generator\PropertyGenerator;
/**
* The `bindProxyProperties` method implementation for access interceptor scope localizers
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*/
class BindProxyProperties extends MethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
parent::__construct(
'bindProxyProperties',
[
new ParameterGenerator('localizedObject', $originalClass->getName()),
new ParameterGenerator('prefixInterceptors', 'array', []),
new ParameterGenerator('suffixInterceptors', 'array', []),
],
static::FLAG_PRIVATE,
null,
"@override constructor to setup interceptors\n\n"
. "@param \\" . $originalClass->getName() . " \$localizedObject\n"
. "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n"
. "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic"
);
$localizedProperties = [];
$properties = Properties::fromReflectionClass($originalClass);
foreach ($properties->getAccessibleProperties() as $property) {
$propertyName = $property->getName();
$localizedProperties[] = '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ';';
}
foreach ($properties->getPrivateProperties() as $property) {
$propertyName = $property->getName();
$localizedProperties[] = "\\Closure::bind(function () use (\$localizedObject) {\n "
. '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";\n"
. '}, $this, ' . var_export($property->getDeclaringClass()->getName(), true)
. ')->__invoke();';
}
$this->setBody(
($localizedProperties ? implode("\n\n", $localizedProperties) . "\n\n" : '')
. '$this->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n"
. '$this->' . $suffixInterceptors->getName() . " = \$suffixInterceptors;"
);
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
@@ -37,30 +39,31 @@ class InterceptedMethod extends MethodGenerator
* @param \Zend\Code\Generator\PropertyGenerator $suffixInterceptors
*
* @return self
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public static function generateMethod(
MethodReflection $originalMethod,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
) : self {
/* @var $method self */
$method = static::fromReflection($originalMethod);
$forwardedParams = array();
$forwardedParams = [];
foreach ($originalMethod->getParameters() as $parameter) {
$forwardedParams[] = '$' . $parameter->getName();
$forwardedParams[] = ($parameter->isVariadic() ? '...' : '') . '$' . $parameter->getName();
}
$method->setDocblock('{@inheritDoc}');
$method->setBody(
InterceptorGenerator::createInterceptedMethodBody(
'$returnValue = parent::'
. $originalMethod->getName() . '(' . implode(', ', $forwardedParams) . ');',
$method,
$prefixInterceptors,
$suffixInterceptors
)
);
$method->setDocBlock('{@inheritDoc}');
$method->setBody(InterceptorGenerator::createInterceptedMethodBody(
'$returnValue = parent::'
. $originalMethod->getName() . '(' . implode(', ', $forwardedParams) . ');',
$method,
$prefixInterceptors,
$suffixInterceptors,
$originalMethod
));
return $method;
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use ReflectionClass;
use Zend\Code\Generator\PropertyGenerator;
@@ -33,6 +36,10 @@ class MagicClone extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
*/
public function __construct(
ReflectionClass $originalClass,
@@ -41,13 +48,14 @@ class MagicClone extends MagicMethodGenerator
) {
parent::__construct($originalClass, '__clone');
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$originalClass->hasMethod('__clone') ? '$returnValue = parent::__clone();' : '$returnValue = null;',
$this,
$prefixInterceptors,
$suffixInterceptors
)
);
$parent = GetMethodIfExists::get($originalClass, '__clone');
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$parent ? '$returnValue = parent::__clone();' : '$returnValue = null;',
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -37,21 +40,24 @@ class MagicGet extends MagicMethodGenerator
* @param ReflectionClass $originalClass
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
parent::__construct($originalClass, '__get', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__get');
$parent = GetMethodIfExists::get($originalClass, '__get');
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($parent ? "{@inheritDoc}\n" : '') . '@param string $name');
if ($override) {
$callParent = '$returnValue = & parent::__get($name);';
} else {
$callParent = '$returnValue = & parent::__get($name);';
if (! $parent) {
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_GET,
'name',
@@ -61,13 +67,12 @@ class MagicGet extends MagicMethodGenerator
);
}
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors
)
);
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -37,21 +40,24 @@ class MagicIsset extends MagicMethodGenerator
* @param ReflectionClass $originalClass
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
parent::__construct($originalClass, '__isset', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__isset', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__isset');
$parent = GetMethodIfExists::get($originalClass, '__isset');
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($parent ? "{@inheritDoc}\n" : '') . '@param string $name');
if ($override) {
$callParent = '$returnValue = & parent::__isset($name);';
} else {
$callParent = '$returnValue = & parent::__isset($name);';
if (! $parent) {
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_ISSET,
'name',
@@ -61,13 +67,12 @@ class MagicIsset extends MagicMethodGenerator
);
}
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors
)
);
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -37,6 +40,9 @@ class MagicSet extends MagicMethodGenerator
* @param \ReflectionClass $originalClass
* @param \Zend\Code\Generator\PropertyGenerator $prefixInterceptors
* @param \Zend\Code\Generator\PropertyGenerator $suffixInterceptors
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
@@ -46,16 +52,16 @@ class MagicSet extends MagicMethodGenerator
parent::__construct(
$originalClass,
'__set',
array(new ParameterGenerator('name'), new ParameterGenerator('value'))
[new ParameterGenerator('name'), new ParameterGenerator('value')]
);
$override = $originalClass->hasMethod('__set');
$parent = GetMethodIfExists::get($originalClass, '__set');
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($parent ? "{@inheritDoc}\n" : '') . '@param string $name');
if ($override) {
$callParent = '$returnValue = & parent::__set($name, $value);';
} else {
$callParent = '$returnValue = & parent::__set($name, $value);';
if (! $parent) {
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_SET,
'name',
@@ -65,13 +71,12 @@ class MagicSet extends MagicMethodGenerator
);
}
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors
)
);
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use ReflectionClass;
use Zend\Code\Generator\PropertyGenerator;
@@ -33,6 +36,10 @@ class MagicSleep extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
*/
public function __construct(
ReflectionClass $originalClass,
@@ -41,17 +48,16 @@ class MagicSleep extends MagicMethodGenerator
) {
parent::__construct($originalClass, '__sleep');
$callParent = $originalClass->hasMethod('__sleep')
? '$returnValue = & parent::__sleep();'
: '$returnValue = array_keys((array) $this);';
$parent = GetMethodIfExists::get($originalClass, '__sleep');
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors
)
);
$callParent = $parent ? '$returnValue = & parent::__sleep();' : '$returnValue = array_keys((array) $this);';
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -37,21 +40,24 @@ class MagicUnset extends MagicMethodGenerator
* @param ReflectionClass $originalClass
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
parent::__construct($originalClass, '__unset', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__unset', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__unset');
$parent = GetMethodIfExists::get($originalClass, '__unset');
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($parent ? "{@inheritDoc}\n" : '') . '@param string $name');
if ($override) {
$callParent = '$returnValue = & parent::__unset($name);';
} else {
$callParent = '$returnValue = & parent::__unset($name);';
if (! $parent) {
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_UNSET,
'name',
@@ -61,13 +67,12 @@ class MagicUnset extends MagicMethodGenerator
);
}
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors
)
);
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -0,0 +1,76 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ReflectionClass;
/**
* The `staticProxyConstructor` implementation for an access interceptor scope localizer proxy
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*/
class StaticProxyConstructor extends MethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(ReflectionClass $originalClass)
{
parent::__construct('staticProxyConstructor', [], static::FLAG_PUBLIC | static::FLAG_STATIC);
$localizedObject = new ParameterGenerator('localizedObject');
$prefix = new ParameterGenerator('prefixInterceptors');
$suffix = new ParameterGenerator('suffixInterceptors');
$localizedObject->setType($originalClass->getName());
$prefix->setDefaultValue([]);
$suffix->setDefaultValue([]);
$prefix->setType('array');
$suffix->setType('array');
$this->setParameter($localizedObject);
$this->setParameter($prefix);
$this->setParameter($suffix);
$this->setReturnType($originalClass->getName());
$this->setDocBlock(
"Constructor to setup interceptors\n\n"
. "@param \\" . $originalClass->getName() . " \$localizedObject\n"
. "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n"
. "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic\n\n"
. '@return self'
);
$this->setBody(
'static $reflection;' . "\n\n"
. '$reflection = $reflection ?: $reflection = new \ReflectionClass(__CLASS__);' . "\n"
. '$instance = $reflection->newInstanceWithoutConstructor();' . "\n\n"
. '$instance->bindProxyProperties($localizedObject, $prefixInterceptors, $suffixInterceptors);' . "\n\n"
. 'return $instance;'
);
}
}

View File

@@ -16,9 +16,12 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Util;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\Util\ProxiedMethodReturnExpression;
use Zend\Code\Generator\PropertyGenerator;
/**
@@ -27,8 +30,7 @@ use Zend\Code\Generator\PropertyGenerator;
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*
* @internal - this class is just here as a small utility for this component,
* don't use it in your own code
* @private - this class is just here as a small utility for this component, don't use it in your own code
*/
class InterceptorGenerator
{
@@ -39,19 +41,21 @@ class InterceptorGenerator
* @param \ProxyManager\Generator\MethodGenerator $method
* @param \Zend\Code\Generator\PropertyGenerator $prefixInterceptors
* @param \Zend\Code\Generator\PropertyGenerator $suffixInterceptors
* @param \ReflectionMethod|null $originalMethod
*
* @return string
*/
public static function createInterceptedMethodBody(
$methodBody,
string $methodBody,
MethodGenerator $method,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
$name = var_export($method->getName(), true);
$prefixInterceptors = $prefixInterceptors->getName();
$suffixInterceptors = $suffixInterceptors->getName();
$params = array();
PropertyGenerator $suffixInterceptors,
?\ReflectionMethod $originalMethod
) : string {
$name = var_export($method->getName(), true);
$prefixInterceptorsName = $prefixInterceptors->getName();
$suffixInterceptorsName = $suffixInterceptors->getName();
$params = [];
foreach ($method->getParameters() as $parameter) {
$parameterName = $parameter->getName();
@@ -60,23 +64,23 @@ class InterceptorGenerator
$paramsString = 'array(' . implode(', ', $params) . ')';
return "if (isset(\$this->$prefixInterceptors" . "[$name])) {\n"
return "if (isset(\$this->$prefixInterceptorsName" . "[$name])) {\n"
. " \$returnEarly = false;\n"
. " \$prefixReturnValue = \$this->$prefixInterceptors" . "[$name]->__invoke("
. " \$prefixReturnValue = \$this->$prefixInterceptorsName" . "[$name]->__invoke("
. "\$this, \$this, $name, $paramsString, \$returnEarly);\n\n"
. " if (\$returnEarly) {\n"
. " return \$prefixReturnValue;\n"
. ' ' . ProxiedMethodReturnExpression::generate('$prefixReturnValue', $originalMethod) . "\n"
. " }\n"
. "}\n\n"
. $methodBody . "\n\n"
. "if (isset(\$this->$suffixInterceptors" . "[$name])) {\n"
. "if (isset(\$this->$suffixInterceptorsName" . "[$name])) {\n"
. " \$returnEarly = false;\n"
. " \$suffixReturnValue = \$this->$suffixInterceptors" . "[$name]->__invoke("
. " \$suffixReturnValue = \$this->$suffixInterceptorsName" . "[$name]->__invoke("
. "\$this, \$this, $name, $paramsString, \$returnValue, \$returnEarly);\n\n"
. " if (\$returnEarly) {\n"
. " return \$suffixReturnValue;\n"
. ' ' . ProxiedMethodReturnExpression::generate('$suffixReturnValue', $originalMethod) . "\n"
. " }\n"
. "}\n\n"
. "return \$returnValue;";
. ProxiedMethodReturnExpression::generate('$returnValue', $originalMethod);
}
}

View File

@@ -16,13 +16,18 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator;
use ProxyManager\Exception\InvalidProxiedClassException;
use ProxyManager\Generator\Util\ClassGeneratorUtils;
use ProxyManager\Proxy\AccessInterceptorInterface;
use ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\SetMethodPrefixInterceptor;
use ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\SetMethodSuffixInterceptor;
use ProxyManager\ProxyGenerator\AccessInterceptor\PropertyGenerator\MethodPrefixInterceptors;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\Constructor;
use ProxyManager\ProxyGenerator\AccessInterceptor\PropertyGenerator\MethodSuffixInterceptors;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\BindProxyProperties;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\InterceptedMethod;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicClone;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicGet;
@@ -30,6 +35,7 @@ use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicSet;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicSleep;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\MagicUnset;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\StaticProxyConstructor;
use ProxyManager\ProxyGenerator\Assertion\CanProxyAssertion;
use ProxyManager\ProxyGenerator\Util\ProxiedMethodsFilter;
use ReflectionClass;
@@ -51,15 +57,19 @@ class AccessInterceptorScopeLocalizerGenerator implements ProxyGeneratorInterfac
{
/**
* {@inheritDoc}
*
* @throws \InvalidArgumentException
* @throws InvalidProxiedClassException
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
{
CanProxyAssertion::assertClassCanBeProxied($originalClass, false);
$classGenerator->setExtendedClass($originalClass->getName());
$classGenerator->setImplementedInterfaces(array('ProxyManager\\Proxy\\AccessInterceptorInterface'));
$classGenerator->setImplementedInterfaces([AccessInterceptorInterface::class]);
$classGenerator->addPropertyFromGenerator($prefixInterceptors = new MethodPrefixInterceptors());
$classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodPrefixInterceptors());
$classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodSuffixInterceptors());
array_map(
function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator) {
@@ -67,20 +77,15 @@ class AccessInterceptorScopeLocalizerGenerator implements ProxyGeneratorInterfac
},
array_merge(
array_map(
function (ReflectionMethod $method) use ($prefixInterceptors, $suffixInterceptors) {
return InterceptedMethod::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$prefixInterceptors,
$suffixInterceptors
);
},
$this->buildMethodInterceptor($prefixInterceptors, $suffixInterceptors),
ProxiedMethodsFilter::getProxiedMethods(
$originalClass,
array('__get', '__set', '__isset', '__unset', '__clone', '__sleep')
['__get', '__set', '__isset', '__unset', '__clone', '__sleep']
)
),
array(
new Constructor($originalClass, $prefixInterceptors, $suffixInterceptors),
[
new StaticProxyConstructor($originalClass),
new BindProxyProperties($originalClass, $prefixInterceptors, $suffixInterceptors),
new SetMethodPrefixInterceptor($prefixInterceptors),
new SetMethodSuffixInterceptor($suffixInterceptors),
new MagicGet($originalClass, $prefixInterceptors, $suffixInterceptors),
@@ -89,8 +94,21 @@ class AccessInterceptorScopeLocalizerGenerator implements ProxyGeneratorInterfac
new MagicUnset($originalClass, $prefixInterceptors, $suffixInterceptors),
new MagicSleep($originalClass, $prefixInterceptors, $suffixInterceptors),
new MagicClone($originalClass, $prefixInterceptors, $suffixInterceptors),
)
]
)
);
}
private function buildMethodInterceptor(
MethodPrefixInterceptors $prefixInterceptors,
MethodSuffixInterceptors $suffixInterceptors
) : callable {
return function (ReflectionMethod $method) use ($prefixInterceptors, $suffixInterceptors) : InterceptedMethod {
return InterceptedMethod::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$prefixInterceptors,
$suffixInterceptors
);
};
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
@@ -38,32 +40,33 @@ class InterceptedMethod extends MethodGenerator
* @param \Zend\Code\Generator\PropertyGenerator $suffixInterceptors
*
* @return self
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public static function generateMethod(
MethodReflection $originalMethod,
PropertyGenerator $valueHolderProperty,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
) : self {
/* @var $method self */
$method = static::fromReflection($originalMethod);
$forwardedParams = array();
$forwardedParams = [];
foreach ($originalMethod->getParameters() as $parameter) {
$forwardedParams[] = '$' . $parameter->getName();
$forwardedParams[] = ($parameter->isVariadic() ? '...' : '') . '$' . $parameter->getName();
}
$method->setDocblock('{@inheritDoc}');
$method->setBody(
InterceptorGenerator::createInterceptedMethodBody(
'$returnValue = $this->' . $valueHolderProperty->getName() . '->'
. $originalMethod->getName() . '(' . implode(', ', $forwardedParams) . ');',
$method,
$valueHolderProperty,
$prefixInterceptors,
$suffixInterceptors
)
);
$method->setDocBlock('{@inheritDoc}');
$method->setBody(InterceptorGenerator::createInterceptedMethodBody(
'$returnValue = $this->' . $valueHolderProperty->getName() . '->'
. $originalMethod->getName() . '(' . implode(', ', $forwardedParams) . ');',
$method,
$valueHolderProperty,
$prefixInterceptors,
$suffixInterceptors,
$originalMethod
));
return $method;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
@@ -32,6 +34,11 @@ class MagicClone extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $valueHolderProperty
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
*/
public function __construct(
ReflectionClass $originalClass,
@@ -52,7 +59,7 @@ class MagicClone extends MagicMethodGenerator
. "}\n\n"
. "foreach (\$this->$suffix as \$key => \$value) {\n"
. " \$this->$suffix" . "[\$key] = clone \$value;\n"
. "}"
. '}'
);
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
@@ -36,6 +39,15 @@ class MagicGet extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $valueHolder
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
* @param PublicPropertiesMap $publicProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
@@ -44,12 +56,12 @@ class MagicGet extends MagicMethodGenerator
PropertyGenerator $suffixInterceptors,
PublicPropertiesMap $publicProperties
) {
parent::__construct($originalClass, '__get', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__get');
$parent = GetMethodIfExists::get($originalClass, '__get');
$valueHolderName = $valueHolder->getName();
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($parent ? "{@inheritDoc}\n" : '') . '@param string $name');
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_GET,
@@ -65,14 +77,13 @@ class MagicGet extends MagicMethodGenerator
. "\n} else {\n $callParent\n}\n\n";
}
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors
)
);
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
@@ -36,6 +39,14 @@ class MagicIsset extends MagicMethodGenerator
{
/**
* Constructor
* @param ReflectionClass $originalClass
* @param PropertyGenerator $valueHolder
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
* @param PublicPropertiesMap $publicProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
@@ -44,12 +55,12 @@ class MagicIsset extends MagicMethodGenerator
PropertyGenerator $suffixInterceptors,
PublicPropertiesMap $publicProperties
) {
parent::__construct($originalClass, '__isset', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__isset', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__isset');
$parent = GetMethodIfExists::get($originalClass, '__isset');
$valueHolderName = $valueHolder->getName();
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($parent ? "{@inheritDoc}\n" : '') . '@param string $name');
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_ISSET,
@@ -65,14 +76,13 @@ class MagicIsset extends MagicMethodGenerator
. "\n} else {\n $callParent\n}\n\n";
}
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors
)
);
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
@@ -36,6 +39,14 @@ class MagicSet extends MagicMethodGenerator
{
/**
* Constructor
* @param ReflectionClass $originalClass
* @param PropertyGenerator $valueHolder
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
* @param PublicPropertiesMap $publicProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
@@ -47,13 +58,13 @@ class MagicSet extends MagicMethodGenerator
parent::__construct(
$originalClass,
'__set',
array(new ParameterGenerator('name'), new ParameterGenerator('value'))
[new ParameterGenerator('name'), new ParameterGenerator('value')]
);
$override = $originalClass->hasMethod('__set');
$parent = GetMethodIfExists::get($originalClass, '__set');
$valueHolderName = $valueHolder->getName();
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($parent ? "{@inheritDoc}\n" : '') . '@param string $name');
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_SET,
@@ -69,14 +80,13 @@ class MagicSet extends MagicMethodGenerator
. "\n} else {\n $callParent\n}\n\n";
}
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors
)
);
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -16,10 +16,13 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\GetMethodIfExists;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Util\InterceptorGenerator;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
@@ -36,6 +39,14 @@ class MagicUnset extends MagicMethodGenerator
{
/**
* Constructor
* @param ReflectionClass $originalClass
* @param PropertyGenerator $valueHolder
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
* @param PublicPropertiesMap $publicProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
@@ -44,12 +55,12 @@ class MagicUnset extends MagicMethodGenerator
PropertyGenerator $suffixInterceptors,
PublicPropertiesMap $publicProperties
) {
parent::__construct($originalClass, '__unset', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__unset', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__unset');
$parent = GetMethodIfExists::get($originalClass, '__unset');
$valueHolderName = $valueHolder->getName();
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($parent ? "{@inheritDoc}\n" : '') . '@param string $name');
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_UNSET,
@@ -67,14 +78,13 @@ class MagicUnset extends MagicMethodGenerator
$callParent .= '$returnValue = false;';
$this->setBody(
InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors
)
);
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}

View File

@@ -0,0 +1,88 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManager\ProxyGenerator\Util\UnsetPropertiesGenerator;
use ReflectionClass;
use Zend\Code\Generator\ParameterGenerator;
use Zend\Code\Generator\PropertyGenerator;
/**
* The `staticProxyConstructor` implementation for access interceptor value holders
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*/
class StaticProxyConstructor extends MethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $valueHolder
* @param PropertyGenerator $prefixInterceptors
* @param PropertyGenerator $suffixInterceptors
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $valueHolder,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
parent::__construct('staticProxyConstructor', [], static::FLAG_PUBLIC | static::FLAG_STATIC);
$prefix = new ParameterGenerator('prefixInterceptors');
$suffix = new ParameterGenerator('suffixInterceptors');
$prefix->setDefaultValue([]);
$suffix->setDefaultValue([]);
$prefix->setType('array');
$suffix->setType('array');
$this->setParameter(new ParameterGenerator('wrappedObject'));
$this->setParameter($prefix);
$this->setParameter($suffix);
$this->setReturnType($originalClass->getName());
$this->setDocBlock(
"Constructor to setup interceptors\n\n"
. "@param \\" . $originalClass->getName() . " \$wrappedObject\n"
. "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n"
. "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic\n\n"
. '@return self'
);
$this->setBody(
'static $reflection;' . "\n\n"
. '$reflection = $reflection ?: $reflection = new \ReflectionClass(__CLASS__);' . "\n"
. '$instance = (new \ReflectionClass(get_class()))->newInstanceWithoutConstructor();' . "\n\n"
. UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'instance')
. '$instance->' . $valueHolder->getName() . " = \$wrappedObject;\n"
. '$instance->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n"
. '$instance->' . $suffixInterceptors->getName() . " = \$suffixInterceptors;\n\n"
. 'return $instance;'
);
}
}

View File

@@ -16,9 +16,12 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Util;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\Util\ProxiedMethodReturnExpression;
use Zend\Code\Generator\PropertyGenerator;
/**
@@ -27,8 +30,7 @@ use Zend\Code\Generator\PropertyGenerator;
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*
* @internal - this class is just here as a small utility for this component,
* don't use it in your own code
* @private - this class is just here as a small utility for this component, don't use it in your own code
*/
class InterceptorGenerator
{
@@ -40,21 +42,23 @@ class InterceptorGenerator
* @param \Zend\Code\Generator\PropertyGenerator $valueHolder
* @param \Zend\Code\Generator\PropertyGenerator $prefixInterceptors
* @param \Zend\Code\Generator\PropertyGenerator $suffixInterceptors
* @param \ReflectionMethod|null $originalMethod
*
* @return string
*/
public static function createInterceptedMethodBody(
$methodBody,
string $methodBody,
MethodGenerator $method,
PropertyGenerator $valueHolder,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
$name = var_export($method->getName(), true);
$valueHolder = $valueHolder->getName();
$prefixInterceptors = $prefixInterceptors->getName();
$suffixInterceptors = $suffixInterceptors->getName();
$params = array();
PropertyGenerator $suffixInterceptors,
?\ReflectionMethod $originalMethod
) : string {
$name = var_export($method->getName(), true);
$valueHolderName = $valueHolder->getName();
$prefixInterceptorsName = $prefixInterceptors->getName();
$suffixInterceptorsName = $suffixInterceptors->getName();
$params = [];
foreach ($method->getParameters() as $parameter) {
$parameterName = $parameter->getName();
@@ -63,23 +67,23 @@ class InterceptorGenerator
$paramsString = 'array(' . implode(', ', $params) . ')';
return "if (isset(\$this->$prefixInterceptors" . "[$name])) {\n"
return "if (isset(\$this->$prefixInterceptorsName" . "[$name])) {\n"
. " \$returnEarly = false;\n"
. " \$prefixReturnValue = \$this->$prefixInterceptors" . "[$name]->__invoke("
. "\$this, \$this->$valueHolder, $name, $paramsString, \$returnEarly);\n\n"
. " \$prefixReturnValue = \$this->$prefixInterceptorsName" . "[$name]->__invoke("
. "\$this, \$this->$valueHolderName, $name, $paramsString, \$returnEarly);\n\n"
. " if (\$returnEarly) {\n"
. " return \$prefixReturnValue;\n"
. ' ' . ProxiedMethodReturnExpression::generate('$prefixReturnValue', $originalMethod) . "\n"
. " }\n"
. "}\n\n"
. $methodBody . "\n\n"
. "if (isset(\$this->$suffixInterceptors" . "[$name])) {\n"
. "if (isset(\$this->$suffixInterceptorsName" . "[$name])) {\n"
. " \$returnEarly = false;\n"
. " \$suffixReturnValue = \$this->$suffixInterceptors" . "[$name]->__invoke("
. "\$this, \$this->$valueHolder, $name, $paramsString, \$returnValue, \$returnEarly);\n\n"
. " \$suffixReturnValue = \$this->$suffixInterceptorsName" . "[$name]->__invoke("
. "\$this, \$this->$valueHolderName, $name, $paramsString, \$returnValue, \$returnEarly);\n\n"
. " if (\$returnEarly) {\n"
. " return \$suffixReturnValue;\n"
. ' ' . ProxiedMethodReturnExpression::generate('$suffixReturnValue', $originalMethod) . "\n"
. " }\n"
. "}\n\n"
. "return \$returnValue;";
. ProxiedMethodReturnExpression::generate('$returnValue', $originalMethod);
}
}

View File

@@ -16,25 +16,31 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator;
use ProxyManager\Exception\InvalidProxiedClassException;
use ProxyManager\Generator\Util\ClassGeneratorUtils;
use ProxyManager\Proxy\AccessInterceptorValueHolderInterface;
use ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\MagicWakeup;
use ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\SetMethodPrefixInterceptor;
use ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator\SetMethodSuffixInterceptor;
use ProxyManager\ProxyGenerator\AccessInterceptor\PropertyGenerator\MethodPrefixInterceptors;
use ProxyManager\ProxyGenerator\AccessInterceptor\PropertyGenerator\MethodSuffixInterceptors;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\Constructor;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\InterceptedMethod;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicClone;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicGet;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicIsset;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicSet;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\MagicUnset;
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolder\MethodGenerator\StaticProxyConstructor;
use ProxyManager\ProxyGenerator\Assertion\CanProxyAssertion;
use ProxyManager\ProxyGenerator\LazyLoadingValueHolder\PropertyGenerator\ValueHolderProperty;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManager\ProxyGenerator\Util\ProxiedMethodsFilter;
use ProxyManager\ProxyGenerator\ValueHolder\MethodGenerator\Constructor;
use ProxyManager\ProxyGenerator\ValueHolder\MethodGenerator\GetWrappedValueHolderValue;
use ProxyManager\ProxyGenerator\ValueHolder\MethodGenerator\MagicSleep;
use ReflectionClass;
@@ -56,16 +62,17 @@ class AccessInterceptorValueHolderGenerator implements ProxyGeneratorInterface
{
/**
* {@inheritDoc}
*
* @throws \InvalidArgumentException
* @throws InvalidProxiedClassException
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
{
CanProxyAssertion::assertClassCanBeProxied($originalClass);
$publicProperties = new PublicPropertiesMap($originalClass);
$interfaces = array(
'ProxyManager\\Proxy\\AccessInterceptorInterface',
'ProxyManager\\Proxy\\ValueHolderInterface',
);
$publicProperties = new PublicPropertiesMap(Properties::fromReflectionClass($originalClass));
$interfaces = [AccessInterceptorValueHolderInterface::class];
if ($originalClass->isInterface()) {
$interfaces[] = $originalClass->getName();
@@ -85,18 +92,12 @@ class AccessInterceptorValueHolderGenerator implements ProxyGeneratorInterface
},
array_merge(
array_map(
function (ReflectionMethod $method) use ($prefixInterceptors, $suffixInterceptors, $valueHolder) {
return InterceptedMethod::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$valueHolder,
$prefixInterceptors,
$suffixInterceptors
);
},
$this->buildMethodInterceptor($prefixInterceptors, $suffixInterceptors, $valueHolder),
ProxiedMethodsFilter::getProxiedMethods($originalClass)
),
array(
new Constructor($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors),
[
Constructor::generateMethod($originalClass, $valueHolder),
new StaticProxyConstructor($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors),
new GetWrappedValueHolderValue($valueHolder),
new SetMethodPrefixInterceptor($prefixInterceptors),
new SetMethodSuffixInterceptor($suffixInterceptors),
@@ -130,9 +131,24 @@ class AccessInterceptorValueHolderGenerator implements ProxyGeneratorInterface
),
new MagicClone($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors),
new MagicSleep($originalClass, $valueHolder),
new MagicWakeup($originalClass, $valueHolder),
)
new MagicWakeup($originalClass),
]
)
);
}
private function buildMethodInterceptor(
MethodPrefixInterceptors $prefixes,
MethodSuffixInterceptors $suffixes,
ValueHolderProperty $valueHolder
) : callable {
return function (ReflectionMethod $method) use ($prefixes, $suffixes, $valueHolder) : InterceptedMethod {
return InterceptedMethod::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$valueHolder,
$prefixes,
$suffixes
);
};
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\Assertion;
use BadMethodCallException;
@@ -47,7 +49,7 @@ final class CanProxyAssertion
*
* @throws InvalidProxiedClassException
*/
public static function assertClassCanBeProxied(ReflectionClass $originalClass, $allowInterfaces = true)
public static function assertClassCanBeProxied(ReflectionClass $originalClass, bool $allowInterfaces = true) : void
{
self::isNotFinal($originalClass);
self::hasNoAbstractProtectedMethods($originalClass);
@@ -62,7 +64,7 @@ final class CanProxyAssertion
*
* @throws InvalidProxiedClassException
*/
private static function isNotFinal(ReflectionClass $originalClass)
private static function isNotFinal(ReflectionClass $originalClass) : void
{
if ($originalClass->isFinal()) {
throw InvalidProxiedClassException::finalClassNotSupported($originalClass);
@@ -74,11 +76,11 @@ final class CanProxyAssertion
*
* @throws InvalidProxiedClassException
*/
private static function hasNoAbstractProtectedMethods(ReflectionClass $originalClass)
private static function hasNoAbstractProtectedMethods(ReflectionClass $originalClass) : void
{
$protectedAbstract = array_filter(
$originalClass->getMethods(),
function (ReflectionMethod $method) {
function (ReflectionMethod $method) : bool {
return $method->isAbstract() && $method->isProtected();
}
);
@@ -93,7 +95,7 @@ final class CanProxyAssertion
*
* @throws InvalidProxiedClassException
*/
private static function isNotInterface(ReflectionClass $originalClass)
private static function isNotInterface(ReflectionClass $originalClass) : void
{
if ($originalClass->isInterface()) {
throw InvalidProxiedClassException::interfaceNotSupported($originalClass);

View File

@@ -0,0 +1,61 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoading\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManager\ProxyGenerator\Util\UnsetPropertiesGenerator;
use Zend\Code\Generator\ParameterGenerator;
use Zend\Code\Generator\PropertyGenerator;
/**
* The `staticProxyConstructor` implementation for lazy loading proxies
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*/
class StaticProxyConstructor extends MethodGenerator
{
/**
* Static constructor
*
* @param PropertyGenerator $initializerProperty
* @param Properties $properties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $initializerProperty, Properties $properties)
{
parent::__construct('staticProxyConstructor', [], static::FLAG_PUBLIC | static::FLAG_STATIC);
$this->setParameter(new ParameterGenerator('initializer'));
$this->setDocBlock("Constructor for lazy initialization\n\n@param \\Closure|null \$initializer");
$this->setBody(
'static $reflection;' . "\n\n"
. '$reflection = $reflection ?: $reflection = new \ReflectionClass(__CLASS__);' . "\n"
. '$instance = (new \ReflectionClass(get_class()))->newInstanceWithoutConstructor();' . "\n\n"
. UnsetPropertiesGenerator::generateSnippet($properties, 'instance')
. '$instance->' . $initializerProperty->getName() . ' = $initializer;' . "\n\n"
. 'return $instance;'
);
}
}

View File

@@ -16,11 +16,15 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionProperty;
use Zend\Code\Generator\PropertyGenerator;
/**
@@ -34,34 +38,160 @@ class CallInitializer extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $initializerProperty
* @param PropertyGenerator $initTracker
* @param Properties $properties
*/
public function __construct(
PropertyGenerator $initializerProperty,
PropertyGenerator $publicPropsDefaults,
PropertyGenerator $initTracker
PropertyGenerator $initTracker,
Properties $properties
) {
parent::__construct(UniqueIdentifierGenerator::getIdentifier('callInitializer'));
$this->setDocblock("Triggers initialization logic for this ghost object");
$docBlock = <<<'DOCBLOCK'
Triggers initialization logic for this ghost object
$this->setParameters(array(
new ParameterGenerator('methodName'),
new ParameterGenerator('parameters', 'array'),
));
@param string $methodName
@param mixed[] $parameters
$this->setVisibility(static::VISIBILITY_PRIVATE);
@return mixed
DOCBLOCK;
parent::__construct(
UniqueIdentifierGenerator::getIdentifier('callInitializer'),
[
new ParameterGenerator('methodName'),
new ParameterGenerator('parameters', 'array'),
],
static::FLAG_PRIVATE,
null,
$docBlock
);
$initializer = $initializerProperty->getName();
$initialization = $initTracker->getName();
$this->setBody(
'if ($this->' . $initialization . ' || ! $this->' . $initializer . ') {' . "\n return;\n}\n\n"
. "\$this->" . $initialization . " = true;\n\n"
. "foreach (self::\$" . $publicPropsDefaults->getName() . " as \$key => \$default) {\n"
. " \$this->\$key = \$default;\n"
. "}\n\n"
. '$this->' . $initializer . '->__invoke'
. '($this, $methodName, $parameters, $this->' . $initializer . ');' . "\n\n"
. "\$this->" . $initialization . " = false;"
$bodyTemplate = <<<'PHP'
if ($this->%s || ! $this->%s) {
return;
}
$this->%s = true;
%s
%s
$result = $this->%s->__invoke($this, $methodName, $parameters, $this->%s, $properties);
$this->%s = false;
return $result;
PHP;
$this->setBody(sprintf(
$bodyTemplate,
$initialization,
$initializer,
$initialization,
$this->propertiesInitializationCode($properties),
$this->propertiesReferenceArrayCode($properties),
$initializer,
$initializer,
$initialization
));
}
private function propertiesInitializationCode(Properties $properties) : string
{
$assignments = [];
foreach ($properties->getAccessibleProperties() as $property) {
$assignments[] = '$this->'
. $property->getName()
. ' = ' . $this->getExportedPropertyDefaultValue($property)
. ';';
}
foreach ($properties->getGroupedPrivateProperties() as $className => $privateProperties) {
$cacheKey = 'cache' . str_replace('\\', '_', $className);
$assignments[] = 'static $' . $cacheKey . ";\n\n"
. '$' . $cacheKey . ' ?: $' . $cacheKey . " = \\Closure::bind(function (\$instance) {\n"
. $this->getPropertyDefaultsAssignments($privateProperties) . "\n"
. '}, null, ' . var_export($className, true) . ");\n\n"
. '$' . $cacheKey . "(\$this);\n\n";
}
return implode("\n", $assignments) . "\n\n";
}
/**
* @param ReflectionProperty[] $properties
*
* @return string
*/
private function getPropertyDefaultsAssignments(array $properties) : string
{
return implode(
"\n",
array_map(
function (ReflectionProperty $property) : string {
return ' $instance->' . $property->getName()
. ' = ' . $this->getExportedPropertyDefaultValue($property) . ';';
},
$properties
)
);
}
private function propertiesReferenceArrayCode(Properties $properties) : string
{
$assignments = [];
foreach ($properties->getAccessibleProperties() as $propertyInternalName => $property) {
$assignments[] = ' '
. var_export($propertyInternalName, true) . ' => & $this->' . $property->getName()
. ',';
}
$code = "\$properties = [\n" . implode("\n", $assignments) . "\n];\n\n";
// must use assignments, as direct reference during array definition causes a fatal error (not sure why)
foreach ($properties->getGroupedPrivateProperties() as $className => $classPrivateProperties) {
$cacheKey = 'cacheFetch' . str_replace('\\', '_', $className);
$code .= 'static $' . $cacheKey . ";\n\n"
. '$' . $cacheKey . ' ?: $' . $cacheKey
. " = \\Closure::bind(function (\$instance, array & \$properties) {\n"
. $this->generatePrivatePropertiesAssignmentsCode($classPrivateProperties)
. "}, \$this, " . var_export($className, true) . ");\n\n"
. '$' . $cacheKey . "(\$this, \$properties);";
}
return $code;
}
/**
* @param ReflectionProperty[] $properties indexed by internal name
*
* @return string
*/
private function generatePrivatePropertiesAssignmentsCode(array $properties) : string
{
$code = '';
foreach ($properties as $property) {
$key = "\0" . $property->getDeclaringClass()->getName() . "\0" . $property->getName();
$code .= ' $properties[' . var_export($key, true) . '] = '
. '& $instance->' . $property->getName() . ";\n";
}
return $code;
}
private function getExportedPropertyDefaultValue(ReflectionProperty $property) : string
{
$name = $property->getName();
$defaults = $property->getDeclaringClass()->getDefaultProperties();
return var_export($defaults[$name] ?? null, true);
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
@@ -32,11 +34,15 @@ class GetProxyInitializer extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $initializerProperty
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $initializerProperty)
{
parent::__construct('getProxyInitializer');
$this->setDocblock('{@inheritDoc}');
$this->setDocBlock('{@inheritDoc}');
$this->setBody('return $this->' . $initializerProperty->getName() . ';');
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
@@ -33,15 +35,21 @@ class InitializeProxy extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $initializerProperty
* @param ZendMethodGenerator $callInitializer
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $initializerProperty, ZendMethodGenerator $callInitializer)
{
parent::__construct('initializeProxy');
$this->setDocblock('{@inheritDoc}');
$this->setDocBlock('{@inheritDoc}');
$this->setReturnType('bool');
$this->setBody(
'return $this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'initializeProxy\', array());'
. '(\'initializeProxy\', []);'
);
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
@@ -32,11 +34,16 @@ class IsProxyInitialized extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $initializerProperty
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $initializerProperty)
{
parent::__construct('isProxyInitialized');
$this->setDocblock('{@inheritDoc}');
$this->setDocBlock('{@inheritDoc}');
$this->setReturnType('bool');
$this->setBody('return ! $this->' . $initializerProperty->getName() . ';');
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
@@ -33,6 +35,10 @@ class MagicClone extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param MethodGenerator $callInitializer
*/
public function __construct(
ReflectionClass $originalClass,
@@ -43,7 +49,7 @@ class MagicClone extends MagicMethodGenerator
$this->setBody(
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__clone\', array());'
. '(\'__clone\', []);'
. ($originalClass->hasMethod('__clone') ? "\n\nparent::__clone();" : '')
);
}

View File

@@ -16,10 +16,15 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializationTracker;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -35,43 +40,120 @@ use Zend\Code\Generator\PropertyGenerator;
class MagicGet extends MagicMethodGenerator
{
/**
* @param \ReflectionClass $originalClass
* @param \Zend\Code\Generator\PropertyGenerator $initializerProperty
* @param \Zend\Code\Generator\MethodGenerator $callInitializer
* @param \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap $publicProperties
* @var string
*/
private $callParentTemplate = <<<'PHP'
$this->%s && ! $this->%s && $this->%s('__get', array('name' => $name));
if (isset(self::$%s[$name])) {
return $this->$name;
}
if (isset(self::$%s[$name])) {
if ($this->%s) {
return $this->$name;
}
// check protected property access via compatible class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$object = isset($caller['object']) ? $caller['object'] : '';
$expectedType = self::$%s[$name];
if ($object instanceof $expectedType) {
return $this->$name;
}
$class = isset($caller['class']) ? $caller['class'] : '';
if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
return $this->$name;
}
} elseif (isset(self::$%s[$name])) {
// check private property access via same class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$class = isset($caller['class']) ? $caller['class'] : '';
static $accessorCache = [];
if (isset(self::$%s[$name][$class])) {
$cacheKey = $class . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(function & ($instance) use ($name) {
return $instance->$name;
}, null, $class);
return $accessor($this);
}
if ($this->%s || 'ReflectionProperty' === $class) {
$tmpClass = key(self::$%s[$name]);
$cacheKey = $tmpClass . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(function & ($instance) use ($name) {
return $instance->$name;
}, null, $tmpClass);
return $accessor($this);
}
}
%s
PHP;
/**
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param MethodGenerator $callInitializer
* @param PublicPropertiesMap $publicProperties
* @param ProtectedPropertiesMap $protectedProperties
* @param PrivatePropertiesMap $privateProperties
* @param InitializationTracker $initializationTracker
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $initializerProperty,
MethodGenerator $callInitializer,
PublicPropertiesMap $publicProperties
PublicPropertiesMap $publicProperties,
ProtectedPropertiesMap $protectedProperties,
PrivatePropertiesMap $privateProperties,
InitializationTracker $initializationTracker
) {
parent::__construct($originalClass, '__get', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__get');
$callParent = '';
$override = $originalClass->hasMethod('__get');
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' return $this->$name;'
. "\n}\n\n";
}
$parentAccess = 'return parent::__get($name);';
if ($override) {
$callParent .= 'return parent::__get($name);';
} else {
$callParent .= PublicScopeSimulator::getPublicAccessSimulationCode(
if (! $override) {
$parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_GET,
'name'
);
}
$this->setBody(
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__get\', array(\'name\' => $name));'
. "\n\n" . $callParent
);
$this->setBody(sprintf(
$this->callParentTemplate,
$initializerProperty->getName(),
$initializationTracker->getName(),
$callInitializer->getName(),
$publicProperties->getName(),
$protectedProperties->getName(),
$initializationTracker->getName(),
$protectedProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$initializationTracker->getName(),
$privateProperties->getName(),
$parentAccess
));
}
}

View File

@@ -16,10 +16,14 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -35,43 +39,110 @@ use Zend\Code\Generator\PropertyGenerator;
class MagicIsset extends MagicMethodGenerator
{
/**
* @param \ReflectionClass $originalClass
* @param \Zend\Code\Generator\PropertyGenerator $initializerProperty
* @param \Zend\Code\Generator\MethodGenerator $callInitializer
* @param \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap $publicProperties
* @var string
*/
private $callParentTemplate = <<<'PHP'
%s
if (isset(self::$%s[$name])) {
return isset($this->$name);
}
if (isset(self::$%s[$name])) {
// check protected property access via compatible class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$object = isset($caller['object']) ? $caller['object'] : '';
$expectedType = self::$%s[$name];
if ($object instanceof $expectedType) {
return isset($this->$name);
}
$class = isset($caller['class']) ? $caller['class'] : '';
if ($class === $expectedType || is_subclass_of($class, $expectedType)) {
return isset($this->$name);
}
} else {
// check private property access via same class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$class = isset($caller['class']) ? $caller['class'] : '';
static $accessorCache = [];
if (isset(self::$%s[$name][$class])) {
$cacheKey = $class . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(function ($instance) use ($name) {
return isset($instance->$name);
}, null, $class);
return $accessor($this);
}
if ('ReflectionProperty' === $class) {
$tmpClass = key(self::$%s[$name]);
$cacheKey = $tmpClass . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(function ($instance) use ($name) {
return isset($instance->$name);
}, null, $tmpClass);
return $accessor($this);
}
}
%s
PHP;
/**
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param MethodGenerator $callInitializer
* @param PublicPropertiesMap $publicProperties
* @param ProtectedPropertiesMap $protectedProperties
* @param PrivatePropertiesMap $privateProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $initializerProperty,
MethodGenerator $callInitializer,
PublicPropertiesMap $publicProperties
PublicPropertiesMap $publicProperties,
ProtectedPropertiesMap $protectedProperties,
PrivatePropertiesMap $privateProperties
) {
parent::__construct($originalClass, '__isset', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__isset', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__isset');
$callParent = '';
$override = $originalClass->hasMethod('__isset');
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' return isset($this->$name);'
. "\n}\n\n";
}
$parentAccess = 'return parent::__isset($name);';
if ($override) {
$callParent .= 'return parent::__isset($name);';
} else {
$callParent .= PublicScopeSimulator::getPublicAccessSimulationCode(
if (! $override) {
$parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_ISSET,
'name'
);
}
$this->setBody(
$this->setBody(sprintf(
$this->callParentTemplate,
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__isset\', array(\'name\' => $name));'
. "\n\n" . $callParent
);
. '(\'__isset\', array(\'name\' => $name));',
$publicProperties->getName(),
$protectedProperties->getName(),
$protectedProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$parentAccess
));
}
}

View File

@@ -16,10 +16,14 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -35,47 +39,116 @@ use Zend\Code\Generator\PropertyGenerator;
class MagicSet extends MagicMethodGenerator
{
/**
* @param \ReflectionClass $originalClass
* @param \Zend\Code\Generator\PropertyGenerator $initializerProperty
* @param \Zend\Code\Generator\MethodGenerator $callInitializer
* @param \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap $publicProperties
* @var string
*/
private $callParentTemplate = <<<'PHP'
%s
if (isset(self::$%s[$name])) {
return ($this->$name = $value);
}
if (isset(self::$%s[$name])) {
// check protected property access via compatible class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$object = isset($caller['object']) ? $caller['object'] : '';
$expectedType = self::$%s[$name];
if ($object instanceof $expectedType) {
return ($this->$name = $value);
}
$class = isset($caller['class']) ? $caller['class'] : '';
if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
return ($this->$name = $value);
}
} elseif (isset(self::$%s[$name])) {
// check private property access via same class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$class = isset($caller['class']) ? $caller['class'] : '';
static $accessorCache = [];
if (isset(self::$%s[$name][$class])) {
$cacheKey = $class . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(function ($instance, $value) use ($name) {
return ($instance->$name = $value);
}, null, $class);
return $accessor($this, $value);
}
if ('ReflectionProperty' === $class) {
$tmpClass = key(self::$%s[$name]);
$cacheKey = $tmpClass . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(function ($instance, $value) use ($name) {
return ($instance->$name = $value);
}, null, $tmpClass);
return $accessor($this, $value);
}
}
%s
PHP;
/**
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param MethodGenerator $callInitializer
* @param PublicPropertiesMap $publicProperties
* @param ProtectedPropertiesMap $protectedProperties
* @param PrivatePropertiesMap $privateProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $initializerProperty,
MethodGenerator $callInitializer,
PublicPropertiesMap $publicProperties
PublicPropertiesMap $publicProperties,
ProtectedPropertiesMap $protectedProperties,
PrivatePropertiesMap $privateProperties
) {
parent::__construct(
$originalClass,
'__set',
array(new ParameterGenerator('name'), new ParameterGenerator('value'))
[new ParameterGenerator('name'), new ParameterGenerator('value')]
);
$override = $originalClass->hasMethod('__set');
$callParent = '';
$override = $originalClass->hasMethod('__set');
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' return ($this->$name = $value);'
. "\n}\n\n";
}
$parentAccess = 'return parent::__set($name, $value);';
if ($override) {
$callParent .= 'return parent::__set($name, $value);';
} else {
$callParent .= PublicScopeSimulator::getPublicAccessSimulationCode(
if (! $override) {
$parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_SET,
'name',
'value'
);
}
$this->setBody(
$this->setBody(sprintf(
$this->callParentTemplate,
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__set\', array(\'name\' => $name, \'value\' => $value));' . "\n\n" . $callParent
);
. '(\'__set\', array(\'name\' => $name, \'value\' => $value));',
$publicProperties->getName(),
$protectedProperties->getName(),
$protectedProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$parentAccess
));
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
@@ -33,6 +35,10 @@ class MagicSleep extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param MethodGenerator $callInitializer
*/
public function __construct(
ReflectionClass $originalClass,
@@ -43,7 +49,7 @@ class MagicSleep extends MagicMethodGenerator
$this->setBody(
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__sleep\', array());' . "\n\n"
. '(\'__sleep\', []);' . "\n\n"
. ($originalClass->hasMethod('__sleep') ? 'return parent::__sleep();' : 'return array_keys((array) $this);')
);
}

View File

@@ -16,10 +16,14 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -35,44 +39,117 @@ use Zend\Code\Generator\PropertyGenerator;
class MagicUnset extends MagicMethodGenerator
{
/**
* @param \ReflectionClass $originalClass
* @param \Zend\Code\Generator\PropertyGenerator $initializerProperty
* @param \Zend\Code\Generator\MethodGenerator $callInitializer
* @param \ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap $publicProperties
* @var string
*/
private $callParentTemplate = <<<'PHP'
%s
if (isset(self::$%s[$name])) {
unset($this->$name);
return;
}
if (isset(self::$%s[$name])) {
// check protected property access via compatible class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$object = isset($caller['object']) ? $caller['object'] : '';
$expectedType = self::$%s[$name];
if ($object instanceof $expectedType) {
unset($this->$name);
return;
}
$class = isset($caller['class']) ? $caller['class'] : '';
if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
unset($this->$name);
return;
}
} elseif (isset(self::$%s[$name])) {
// check private property access via same class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$class = isset($caller['class']) ? $caller['class'] : '';
static $accessorCache = [];
if (isset(self::$%s[$name][$class])) {
$cacheKey = $class . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(function ($instance) use ($name) {
unset($instance->$name);
}, null, $class);
return $accessor($this);
}
if ('ReflectionProperty' === $class) {
$tmpClass = key(self::$%s[$name]);
$cacheKey = $tmpClass . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(function ($instance) use ($name) {
unset($instance->$name);
}, null, $tmpClass);
return $accessor($this);
}
}
%s
PHP;
/**
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param MethodGenerator $callInitializer
* @param PublicPropertiesMap $publicProperties
* @param ProtectedPropertiesMap $protectedProperties
* @param PrivatePropertiesMap $privateProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $initializerProperty,
MethodGenerator $callInitializer,
PublicPropertiesMap $publicProperties
PublicPropertiesMap $publicProperties,
ProtectedPropertiesMap $protectedProperties,
PrivatePropertiesMap $privateProperties
) {
parent::__construct($originalClass, '__unset', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__unset', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__unset');
$callParent = '';
$override = $originalClass->hasMethod('__unset');
$this->setDocblock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($override ? "{@inheritDoc}\n" : '') . '@param string $name');
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' unset($this->$name);'
. "\n\n return;"
. "\n}\n\n";
}
$parentAccess = 'return parent::__unset($name);';
if ($override) {
$callParent .= "return parent::__unset(\$name);";
} else {
$callParent .= PublicScopeSimulator::getPublicAccessSimulationCode(
if (! $override) {
$parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_UNSET,
'name'
);
}
$this->setBody(
$this->setBody(sprintf(
$this->callParentTemplate,
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__unset\', array(\'name\' => $name));'
. "\n\n" . $callParent
);
. '(\'__unset\', array(\'name\' => $name));',
$publicProperties->getName(),
$protectedProperties->getName(),
$protectedProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$parentAccess
));
}
}

View File

@@ -16,10 +16,12 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use Zend\Code\Generator\PropertyGenerator;
/**
@@ -33,17 +35,17 @@ class SetProxyInitializer extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $initializerProperty
*/
public function __construct(PropertyGenerator $initializerProperty)
{
parent::__construct('setProxyInitializer');
$initializerParameter = new ParameterGenerator('initializer');
$initializerParameter->setType('Closure');
$initializerParameter->setDefaultValue(null);
$this->setParameter($initializerParameter);
$this->setDocblock('{@inheritDoc}');
$this->setBody('$this->' . $initializerProperty->getName() . ' = $initializer;');
parent::__construct(
'setProxyInitializer',
[(new ParameterGenerator('initializer', 'Closure'))->setDefaultValue(null)],
self::FLAG_PUBLIC,
'$this->' . $initializerProperty->getName() . ' = $initializer;',
'{@inheritDoc}'
);
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
@@ -31,13 +33,15 @@ class InitializationTracker extends PropertyGenerator
{
/**
* Constructor
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct()
{
parent::__construct(UniqueIdentifierGenerator::getIdentifier('initializationTracker'));
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocblock('@var bool tracks initialization status - true while the object is initializing');
$this->setDocBlock('@var bool tracks initialization status - true while the object is initializing');
$this->setDefaultValue(false);
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
@@ -31,12 +33,14 @@ class InitializerProperty extends PropertyGenerator
{
/**
* Constructor
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct()
{
parent::__construct(UniqueIdentifierGenerator::getIdentifier('initializer'));
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocblock('@var \\Closure|null initializer responsible for generating the wrapped object');
$this->setDocBlock('@var \\Closure|null initializer responsible for generating the wrapped object');
}
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use Zend\Code\Generator\PropertyGenerator;
/**
* Property that contains the initializer for a lazy object
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*/
class PrivatePropertiesMap extends PropertyGenerator
{
const KEY_DEFAULT_VALUE = 'defaultValue';
/**
* Constructor
*
* @param Properties $properties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(Properties $properties)
{
parent::__construct(
UniqueIdentifierGenerator::getIdentifier('privateProperties')
);
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setStatic(true);
$this->setDocBlock(
'@var array[][] visibility and default value of defined properties, indexed by property name and class name'
);
$this->setDefaultValue($this->getMap($properties));
}
/**
* @param Properties $properties
*
* @return int[][]|mixed[][]
*/
private function getMap(Properties $properties) : array
{
$map = [];
foreach ($properties->getPrivateProperties() as $property) {
$propertyKey = & $map[$property->getName()];
$propertyKey[$property->getDeclaringClass()->getName()] = true;
}
return $map;
}
}

View File

@@ -0,0 +1,74 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use Zend\Code\Generator\PropertyGenerator;
/**
* Property that contains the protected instance lazy-loadable properties of an object
*
* @author Marco Pivetta <ocramius@gmail.com>
* @license MIT
*/
class ProtectedPropertiesMap extends PropertyGenerator
{
const KEY_DEFAULT_VALUE = 'defaultValue';
/**
* Constructor
*
* @param Properties $properties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(Properties $properties)
{
parent::__construct(
UniqueIdentifierGenerator::getIdentifier('protectedProperties')
);
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setStatic(true);
$this->setDocBlock(
'@var string[][] declaring class name of defined protected properties, indexed by property name'
);
$this->setDefaultValue($this->getMap($properties));
}
/**
*
* @param Properties $properties
*
* @return int[][]|mixed[][]
*/
private function getMap(Properties $properties) : array
{
$map = [];
foreach ($properties->getProtectedProperties() as $property) {
$map[$property->getName()] = $property->getDeclaringClass()->getName();
}
return $map;
}
}

View File

@@ -16,16 +16,20 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator;
use ProxyManager\Exception\InvalidProxiedClassException;
use ProxyManager\Generator\MethodGenerator as ProxyManagerMethodGenerator;
use ProxyManager\Generator\Util\ClassGeneratorUtils;
use ProxyManager\Proxy\GhostObjectInterface;
use ProxyManager\ProxyGenerator\Assertion\CanProxyAssertion;
use ProxyManager\ProxyGenerator\LazyLoading\MethodGenerator\Constructor;
use ProxyManager\ProxyGenerator\LazyLoading\MethodGenerator\StaticProxyConstructor;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\CallInitializer;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\GetProxyInitializer;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\InitializeProxy;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\IsProxyInitialized;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\LazyLoadingMethodInterceptor;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicClone;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicIsset;
@@ -35,8 +39,10 @@ use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicUnset;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\SetProxyInitializer;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializationTracker;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializerProperty;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesDefaults;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap;
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManager\ProxyGenerator\Util\ProxiedMethodsFilter;
use ReflectionClass;
use ReflectionMethod;
@@ -56,59 +62,104 @@ class LazyLoadingGhostGenerator implements ProxyGeneratorInterface
{
/**
* {@inheritDoc}
*
* @throws InvalidProxiedClassException
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator, array $proxyOptions = [])
{
CanProxyAssertion::assertClassCanBeProxied($originalClass);
CanProxyAssertion::assertClassCanBeProxied($originalClass, false);
$interfaces = array('ProxyManager\\Proxy\\GhostObjectInterface');
$publicProperties = new PublicPropertiesMap($originalClass);
$publicPropsDefaults = new PublicPropertiesDefaults($originalClass);
$filteredProperties = Properties::fromReflectionClass($originalClass)
->filter($proxyOptions['skippedProperties'] ?? []);
if ($originalClass->isInterface()) {
$interfaces[] = $originalClass->getName();
} else {
$classGenerator->setExtendedClass($originalClass->getName());
}
$publicProperties = new PublicPropertiesMap($filteredProperties);
$privateProperties = new PrivatePropertiesMap($filteredProperties);
$protectedProperties = new ProtectedPropertiesMap($filteredProperties);
$classGenerator->setImplementedInterfaces($interfaces);
$classGenerator->setExtendedClass($originalClass->getName());
$classGenerator->setImplementedInterfaces([GhostObjectInterface::class]);
$classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty());
$classGenerator->addPropertyFromGenerator($initializationTracker = new InitializationTracker());
$classGenerator->addPropertyFromGenerator($publicProperties);
$classGenerator->addPropertyFromGenerator($publicPropsDefaults);
$classGenerator->addPropertyFromGenerator($privateProperties);
$classGenerator->addPropertyFromGenerator($protectedProperties);
$init = new CallInitializer($initializer, $publicPropsDefaults, $initializationTracker);
$init = new CallInitializer($initializer, $initializationTracker, $filteredProperties);
array_map(
function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator) {
ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
},
array_merge(
array_map(
function (ReflectionMethod $method) use ($initializer, $init) {
return LazyLoadingMethodInterceptor::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$initializer,
$init
);
},
ProxiedMethodsFilter::getProxiedMethods($originalClass)
),
array(
$this->getAbstractProxiedMethods($originalClass),
[
$init,
new Constructor($originalClass, $initializer),
new MagicGet($originalClass, $initializer, $init, $publicProperties),
new MagicSet($originalClass, $initializer, $init, $publicProperties),
new MagicIsset($originalClass, $initializer, $init, $publicProperties),
new MagicUnset($originalClass, $initializer, $init, $publicProperties),
new MagicClone($originalClass, $initializer, $init, $publicProperties),
new MagicSleep($originalClass, $initializer, $init, $publicProperties),
new StaticProxyConstructor($initializer, $filteredProperties),
new MagicGet(
$originalClass,
$initializer,
$init,
$publicProperties,
$protectedProperties,
$privateProperties,
$initializationTracker
),
new MagicSet(
$originalClass,
$initializer,
$init,
$publicProperties,
$protectedProperties,
$privateProperties
),
new MagicIsset(
$originalClass,
$initializer,
$init,
$publicProperties,
$protectedProperties,
$privateProperties
),
new MagicUnset(
$originalClass,
$initializer,
$init,
$publicProperties,
$protectedProperties,
$privateProperties
),
new MagicClone($originalClass, $initializer, $init),
new MagicSleep($originalClass, $initializer, $init),
new SetProxyInitializer($initializer),
new GetProxyInitializer($initializer),
new InitializeProxy($initializer, $init),
new IsProxyInitialized($initializer),
)
]
)
);
}
/**
* Retrieves all abstract methods to be proxied
*
* @param ReflectionClass $originalClass
*
* @return MethodGenerator[]
*/
private function getAbstractProxiedMethods(ReflectionClass $originalClass) : array
{
return array_map(
function (ReflectionMethod $method) : ProxyManagerMethodGenerator {
$generated = ProxyManagerMethodGenerator
::fromReflection(new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()));
$generated->setAbstract(false);
return $generated;
},
ProxiedMethodsFilter::getAbstractProxiedMethods($originalClass)
);
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
@@ -32,11 +34,15 @@ class GetProxyInitializer extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $initializerProperty
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $initializerProperty)
{
parent::__construct('getProxyInitializer');
$this->setDocblock('{@inheritDoc}');
$this->setDocBlock('{@inheritDoc}');
$this->setBody('return $this->' . $initializerProperty->getName() . ';');
}
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
@@ -32,11 +34,17 @@ class InitializeProxy extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $initializerProperty
* @param PropertyGenerator $valueHolderProperty
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $initializerProperty, PropertyGenerator $valueHolderProperty)
{
parent::__construct('initializeProxy');
$this->setDocblock('{@inheritDoc}');
$this->setDocBlock('{@inheritDoc}');
$this->setReturnType('bool');
$initializer = $initializerProperty->getName();

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
@@ -32,11 +34,16 @@ class IsProxyInitialized extends MethodGenerator
{
/**
* Constructor
*
* @param PropertyGenerator $valueHolderProperty
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public function __construct(PropertyGenerator $valueHolderProperty)
{
parent::__construct('isProxyInitialized');
$this->setDocblock('{@inheritDoc}');
$this->setDocBlock('{@inheritDoc}');
$this->setReturnType('bool');
$this->setBody('return null !== $this->' . $valueHolderProperty->getName() . ';');
}
}

View File

@@ -16,9 +16,12 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\Util\ProxiedMethodReturnExpression;
use Zend\Code\Generator\PropertyGenerator;
use Zend\Code\Reflection\MethodReflection;
@@ -35,26 +38,29 @@ class LazyLoadingMethodInterceptor extends MethodGenerator
* @param \Zend\Code\Generator\PropertyGenerator $initializerProperty
* @param \Zend\Code\Generator\PropertyGenerator $valueHolderProperty
*
* @return LazyLoadingMethodInterceptor|static
* @return self
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
*/
public static function generateMethod(
MethodReflection $originalMethod,
PropertyGenerator $initializerProperty,
PropertyGenerator $valueHolderProperty
) {
) : self {
/* @var $method self */
$method = static::fromReflection($originalMethod);
$initializerName = $initializerProperty->getName();
$valueHolderName = $valueHolderProperty->getName();
$parameters = $originalMethod->getParameters();
$methodName = $originalMethod->getName();
$initializerParams = array();
$forwardedParams = array();
$initializerParams = [];
$forwardedParams = [];
foreach ($parameters as $parameter) {
$parameterName = $parameter->getName();
$variadicPrefix = $parameter->isVariadic() ? '...' : '';
$initializerParams[] = var_export($parameterName, true) . ' => $' . $parameterName;
$forwardedParams[] = '$' . $parameterName;
$forwardedParams[] = $variadicPrefix . '$' . $parameterName;
}
$method->setBody(
@@ -62,10 +68,12 @@ class LazyLoadingMethodInterceptor extends MethodGenerator
. ' && $this->' . $initializerName
. '->__invoke($this->' . $valueHolderName . ', $this, ' . var_export($methodName, true)
. ', array(' . implode(', ', $initializerParams) . '), $this->' . $initializerName . ");\n\n"
. 'return $this->' . $valueHolderName . '->'
. $methodName . '(' . implode(', ', $forwardedParams) . ');'
. ProxiedMethodReturnExpression::generate(
'$this->' . $valueHolderName . '->' . $methodName . '(' . implode(', ', $forwardedParams) . ')',
$originalMethod
)
);
$method->setDocblock('{@inheritDoc}');
$method->setDocBlock('{@inheritDoc}');
return $method;
}

View File

@@ -16,6 +16,8 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
@@ -32,6 +34,10 @@ class MagicClone extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param PropertyGenerator $valueHolderProperty
*/
public function __construct(
ReflectionClass $originalClass,

View File

@@ -16,10 +16,12 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -35,6 +37,14 @@ class MagicGet extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param PropertyGenerator $valueHolderProperty
* @param PublicPropertiesMap $publicProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
@@ -42,9 +52,11 @@ class MagicGet extends MagicMethodGenerator
PropertyGenerator $valueHolderProperty,
PublicPropertiesMap $publicProperties
) {
parent::__construct($originalClass, '__get', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]);
$this->setDocblock(($originalClass->hasMethod('__get') ? "{@inheritDoc}\n" : '') . '@param string $name');
$hasParent = $originalClass->hasMethod('__get');
$this->setDocBlock(($hasParent ? "{@inheritDoc}\n" : '') . '@param string $name');
$initializer = $initializerProperty->getName();
$valueHolder = $valueHolderProperty->getName();
@@ -52,16 +64,33 @@ class MagicGet extends MagicMethodGenerator
. ' return $this->' . $valueHolder . '->$name;'
. "\n}\n\n";
$callParent .= PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_GET,
'name',
null,
$valueHolderProperty
);
if ($hasParent) {
$this->setInitializerBody(
$initializer,
$valueHolder,
$callParent . 'return $this->' . $valueHolder . '->__get($name);'
);
return;
}
$this->setInitializerBody(
$initializer,
$valueHolder,
$callParent . PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_GET,
'name',
null,
$valueHolderProperty
)
);
}
private function setInitializerBody(string $initializer, string $valueHolder, string $callParent) : void
{
$this->setBody(
'$this->' . $initializer . ' && $this->' . $initializer
. '->__invoke($this->' . $valueHolder . ', $this, \'__get\', array(\'name\' => $name), $this->'
. '->__invoke($this->' . $valueHolder . ', $this, \'__get\', [\'name\' => $name], $this->'
. $initializer . ');'
. "\n\n" . $callParent
);

View File

@@ -16,10 +16,12 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -35,6 +37,14 @@ class MagicIsset extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param PropertyGenerator $valueHolderProperty
* @param PublicPropertiesMap $publicProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
@@ -42,13 +52,13 @@ class MagicIsset extends MagicMethodGenerator
PropertyGenerator $valueHolderProperty,
PublicPropertiesMap $publicProperties
) {
parent::__construct($originalClass, '__isset', array(new ParameterGenerator('name')));
parent::__construct($originalClass, '__isset', [new ParameterGenerator('name')]);
$initializer = $initializerProperty->getName();
$valueHolder = $valueHolderProperty->getName();
$callParent = '';
$this->setDocblock(($originalClass->hasMethod('__isset') ? "{@inheritDoc}\n" : '') . '@param string $name');
$this->setDocBlock(($originalClass->hasMethod('__isset') ? "{@inheritDoc}\n" : '') . '@param string $name');
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"

View File

@@ -16,10 +16,12 @@
* and is licensed under the MIT license.
*/
declare(strict_types=1);
namespace ProxyManager\ProxyGenerator\LazyLoadingValueHolder\MethodGenerator;
use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use Zend\Code\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
use ReflectionClass;
@@ -35,6 +37,14 @@ class MagicSet extends MagicMethodGenerator
{
/**
* Constructor
*
* @param ReflectionClass $originalClass
* @param PropertyGenerator $initializerProperty
* @param PropertyGenerator $valueHolderProperty
* @param PublicPropertiesMap $publicProperties
*
* @throws \Zend\Code\Generator\Exception\InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
@@ -45,16 +55,15 @@ class MagicSet extends MagicMethodGenerator
parent::__construct(
$originalClass,
'__set',
array(new ParameterGenerator('name'), new ParameterGenerator('value'))
[new ParameterGenerator('name'), new ParameterGenerator('value')]
);
$hasParent = $originalClass->hasMethod('__set');
$initializer = $initializerProperty->getName();
$valueHolder = $valueHolderProperty->getName();
$callParent = '';
$this->setDocblock(
($originalClass->hasMethod('__set') ? "{@inheritDoc}\n" : '') . "@param string \$name\n@param mixed \$value"
);
$this->setDocBlock(($hasParent ? "{@inheritDoc}\n" : '') . "@param string \$name\n@param mixed \$value");
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
@@ -62,12 +71,14 @@ class MagicSet extends MagicMethodGenerator
. "\n}\n\n";
}
$callParent .= PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_SET,
'name',
'value',
$valueHolderProperty
);
$callParent .= $hasParent
? 'return $this->' . $valueHolder . '->__set($name, $value);'
: PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_SET,
'name',
'value',
$valueHolderProperty
);
$this->setBody(
'$this->' . $initializer . ' && $this->' . $initializer

Some files were not shown because too many files have changed in this diff Show More