-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(coroutines): added custom proxy type instead of lazy loading valu…
…e holder to get rid of shared lazy tmp object access
- Loading branch information
1 parent
1632b47
commit df3da24
Showing
23 changed files
with
662 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
'tests/Unit/Server/Php8', | ||
'vendor', | ||
'hack', | ||
'ext', | ||
]); | ||
|
||
$config = new PhpCsFixer\Config(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace K911\Swoole\Bridge\Symfony\Container\Proxy; | ||
|
||
use K911\Swoole\Bridge\Symfony\Container\ServicePool\ServicePool; | ||
|
||
/** | ||
* @template RealObjectType of object | ||
*/ | ||
interface ContextualProxy | ||
{ | ||
/** | ||
* @return ServicePool<RealObjectType> | ||
*/ | ||
public function getServicePool(): ServicePool; | ||
|
||
/** | ||
* @param ServicePool<RealObjectType> $servicePool | ||
* | ||
* @return ContextualProxy<RealObjectType>&RealObjectType | ||
*/ | ||
public static function staticProxyConstructor(ServicePool $servicePool): object; | ||
} |
53 changes: 53 additions & 0 deletions
53
src/Bridge/Symfony/Container/Proxy/Generation/ContextualAccessForwarderFactory.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace K911\Swoole\Bridge\Symfony\Container\Proxy\Generation; | ||
|
||
use K911\Swoole\Bridge\Symfony\Container\Proxy\ContextualProxy; | ||
use K911\Swoole\Bridge\Symfony\Container\ServicePool\ServicePool; | ||
use ProxyManager\Configuration; | ||
use ProxyManager\Factory\AbstractBaseFactory; | ||
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface; | ||
use ProxyManager\Signature\Exception\InvalidSignatureException; | ||
use ProxyManager\Signature\Exception\MissingSignatureException; | ||
|
||
/** | ||
* Factory responsible of producing proxy objects. | ||
*/ | ||
class ContextualAccessForwarderFactory extends AbstractBaseFactory | ||
{ | ||
private $generator; | ||
|
||
public function __construct(?Configuration $configuration = null) | ||
{ | ||
parent::__construct($configuration); | ||
|
||
$this->generator = new ContextualAccessForwarderGenerator(new MethodForwarderBuilder()); | ||
} | ||
|
||
/** | ||
* @template RealObjectType of object | ||
* | ||
* @param ServicePool<RealObjectType> $servicePool | ||
* @param class-string<RealObjectType> $serviceClass | ||
* | ||
* @throws InvalidSignatureException | ||
* @throws MissingSignatureException | ||
* @throws \OutOfBoundsException | ||
* | ||
* @return ContextualProxy<RealObjectType>&RealObjectType | ||
*/ | ||
public function createProxy(ServicePool $servicePool, string $serviceClass) | ||
{ | ||
/** @var class-string<ContextualProxy<RealObjectType>&RealObjectType> $proxyClassName */ | ||
$proxyClassName = $this->generateProxy($serviceClass); | ||
|
||
return $proxyClassName::staticProxyConstructor($servicePool); | ||
} | ||
|
||
protected function getGenerator(): ProxyGeneratorInterface | ||
{ | ||
return $this->generator; | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
src/Bridge/Symfony/Container/Proxy/Generation/ContextualAccessForwarderGenerator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace K911\Swoole\Bridge\Symfony\Container\Proxy\Generation; | ||
|
||
use K911\Swoole\Bridge\Symfony\Container\Proxy\ContextualProxy; | ||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator\GetWrappedServicePoolValue; | ||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator\MagicGet; | ||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator\MagicSet; | ||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator\StaticProxyConstructor; | ||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\PropertyGenerator\ServicePoolProperty; | ||
use Laminas\Code\Generator\ClassGenerator; | ||
use Laminas\Code\Generator\MethodGenerator; | ||
use ProxyManager\Exception\InvalidProxiedClassException; | ||
use ProxyManager\Generator\Util\ClassGeneratorUtils; | ||
use ProxyManager\ProxyGenerator\Assertion\CanProxyAssertion; | ||
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap; | ||
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface; | ||
use ProxyManager\ProxyGenerator\Util\Properties; | ||
use ProxyManager\ProxyGenerator\Util\ProxiedMethodsFilter; | ||
|
||
/** | ||
* Generator for proxies with service pool. | ||
*/ | ||
class ContextualAccessForwarderGenerator implements ProxyGeneratorInterface | ||
{ | ||
public function __construct(private MethodForwarderBuilder $forwarderBuilder) | ||
{ | ||
} | ||
|
||
/** | ||
* @template T of object | ||
* | ||
* @param \ReflectionClass<T> $originalClass | ||
* | ||
* @throws \InvalidArgumentException | ||
* @throws InvalidProxiedClassException | ||
*/ | ||
public function generate(\ReflectionClass $originalClass, ClassGenerator $classGenerator): void | ||
{ | ||
CanProxyAssertion::assertClassCanBeProxied($originalClass); | ||
|
||
$interfaces = [ | ||
ContextualProxy::class, | ||
]; | ||
|
||
if ($originalClass->isInterface()) { | ||
$interfaces[] = $originalClass->getName(); | ||
} | ||
|
||
if (!$originalClass->isInterface()) { | ||
$classGenerator->setExtendedClass($originalClass->getName()); | ||
} | ||
|
||
$publicProperties = new PublicPropertiesMap(Properties::fromReflectionClass($originalClass)); | ||
$classGenerator->setImplementedInterfaces($interfaces); | ||
$classGenerator->addPropertyFromGenerator($servicePoolProperty = new ServicePoolProperty()); | ||
$classGenerator->addPropertyFromGenerator($publicProperties); | ||
$closure = static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator): void { | ||
ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod); | ||
}; | ||
|
||
array_map( | ||
$closure, | ||
array_merge( | ||
array_map( | ||
$this->forwarderBuilder->buildMethodInterceptor($servicePoolProperty), | ||
ProxiedMethodsFilter::getProxiedMethods($originalClass) | ||
), | ||
[ | ||
new StaticProxyConstructor($servicePoolProperty, Properties::fromReflectionClass($originalClass)), | ||
new GetWrappedServicePoolValue($servicePoolProperty), | ||
new MagicGet($originalClass, $servicePoolProperty, $publicProperties), | ||
new MagicSet($originalClass, $servicePoolProperty, $publicProperties), | ||
] | ||
) | ||
); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/Bridge/Symfony/Container/Proxy/Generation/MethodForwarderBuilder.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace K911\Swoole\Bridge\Symfony\Container\Proxy\Generation; | ||
|
||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator\ForwardedMethod; | ||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\PropertyGenerator\ServicePoolProperty; | ||
use Laminas\Code\Reflection\MethodReflection; | ||
|
||
final class MethodForwarderBuilder | ||
{ | ||
public function buildMethodInterceptor(ServicePoolProperty $servicePoolHolderProperty): callable | ||
{ | ||
return static function (\ReflectionMethod $method) use ($servicePoolHolderProperty): ForwardedMethod { | ||
return ForwardedMethod::generateMethod( | ||
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()), | ||
$servicePoolHolderProperty | ||
); | ||
}; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
src/Bridge/Symfony/Container/Proxy/Generation/MethodGenerator/ForwardedMethod.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator; | ||
|
||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator\Util\MethodForwarderGenerator; | ||
use Laminas\Code\Generator\Exception\InvalidArgumentException; | ||
use Laminas\Code\Generator\PropertyGenerator; | ||
use Laminas\Code\Reflection\MethodReflection; | ||
use ProxyManager\Generator\MethodGenerator; | ||
|
||
/** | ||
* Method with additional pre- and post- interceptor logic in the body. | ||
*/ | ||
class ForwardedMethod extends MethodGenerator | ||
{ | ||
/** | ||
* @throws InvalidArgumentException | ||
*/ | ||
public static function generateMethod( | ||
MethodReflection $originalMethod, | ||
PropertyGenerator $servicePoolHolderProperty | ||
): self { | ||
$method = static::fromReflectionWithoutBodyAndDocBlock($originalMethod); | ||
$forwardedParams = []; | ||
|
||
foreach ($originalMethod->getParameters() as $parameter) { | ||
$forwardedParams[] = ($parameter->isVariadic() ? '...' : '').'$'.$parameter->getName(); | ||
} | ||
|
||
$method->setBody(MethodForwarderGenerator::createForwardedMethodBody( | ||
$originalMethod->getName().'('.implode(', ', $forwardedParams).')', | ||
$servicePoolHolderProperty, | ||
$originalMethod | ||
)); | ||
|
||
return $method; | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/Bridge/Symfony/Container/Proxy/Generation/MethodGenerator/GetWrappedServicePoolValue.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator; | ||
|
||
use K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\PropertyGenerator\ServicePoolProperty; | ||
use K911\Swoole\Bridge\Symfony\Container\ServicePool\ServicePool; | ||
use Laminas\Code\Generator\Exception\InvalidArgumentException; | ||
use ProxyManager\Generator\MethodGenerator; | ||
|
||
/** | ||
* Implementation for {@see \ProxyManager\Proxy\ValueHolderInterface::getWrappedValueHolderValue} | ||
* for lazy loading value holder objects. | ||
*/ | ||
class GetWrappedServicePoolValue extends MethodGenerator | ||
{ | ||
/** | ||
* Constructor. | ||
* | ||
* @throws InvalidArgumentException | ||
*/ | ||
public function __construct(ServicePoolProperty $servicePoolHolderProperty) | ||
{ | ||
parent::__construct('getServicePool'); | ||
$this->setBody('return $this->'.$servicePoolHolderProperty->getName().';'); | ||
$this->setReturnType(ServicePool::class); | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
src/Bridge/Symfony/Container/Proxy/Generation/MethodGenerator/MagicGet.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace K911\Swoole\Bridge\Symfony\Container\Proxy\Generation\MethodGenerator; | ||
|
||
use Laminas\Code\Generator\ParameterGenerator; | ||
use Laminas\Code\Generator\PropertyGenerator; | ||
use ProxyManager\Generator\MagicMethodGenerator; | ||
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap; | ||
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator; | ||
|
||
/** | ||
* Magic `__get` for lazy loading value holder objects. | ||
*/ | ||
class MagicGet extends MagicMethodGenerator | ||
{ | ||
/** | ||
* Constructor. | ||
* | ||
* @template T of object | ||
* | ||
* @param \ReflectionClass<T> $originalClass | ||
* | ||
* @throws \InvalidArgumentException | ||
*/ | ||
public function __construct( | ||
\ReflectionClass $originalClass, | ||
PropertyGenerator $servicePoolProperty, | ||
PublicPropertiesMap $publicProperties | ||
) { | ||
parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]); | ||
|
||
$hasParent = $originalClass->hasMethod('__get'); | ||
|
||
$servicePool = $servicePoolProperty->getName(); | ||
$callParent = 'if (isset(self::$'.$publicProperties->getName()."[\$name])) {\n" | ||
.' return $this->'.$servicePool.'->get()->$name;' | ||
."\n}\n\n"; | ||
|
||
if ($hasParent) { | ||
$this->setBody( | ||
$callParent.'return $this->'.$servicePool.'->get()->__get($name);' | ||
); | ||
|
||
return; | ||
} | ||
|
||
$this->setBody( | ||
$callParent.PublicScopeSimulator::getPublicAccessSimulationCode( | ||
PublicScopeSimulator::OPERATION_GET, | ||
'name', | ||
null, | ||
new PropertyGenerator($servicePool.'->get()'), | ||
null, | ||
$originalClass | ||
) | ||
); | ||
} | ||
} |
Oops, something went wrong.