Skip to content

Commit

Permalink
Fix enums and new in initializers as default values on PHP 8.1
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Apr 27, 2022
1 parent c828ced commit 38fe500
Show file tree
Hide file tree
Showing 17 changed files with 174 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/ProxyManager/Factory/AbstractBaseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace ProxyManager\Factory;

use Laminas\Code\Generator\ClassGenerator;
use OutOfBoundsException;
use ProxyManager\Configuration;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
use ProxyManager\Signature\Exception\InvalidSignatureException;
use ProxyManager\Signature\Exception\MissingSignatureException;
Expand Down
20 changes: 18 additions & 2 deletions src/ProxyManager/Generator/ClassGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,30 @@
namespace ProxyManager\Generator;

use Laminas\Code\Generator\ClassGenerator as LaminasClassGenerator;
use ProxyManager\Generator\ValueGenerator;
use ReflectionParameter;

use function method_exists;

/**
* Class generator that ensures that interfaces/classes that are implemented/extended are FQCNs
*
* @internal do not use this in your code: it is only here for internal use
* @deprecated this class was in use due to parent implementation not receiving prompt bugfixes, but
* `laminas/laminas-code` is actively maintained and receives quick release iterations.
*/
class ClassGenerator extends LaminasClassGenerator
{
public function generate(): string
{
$extendedClass = $this->getExtendedClass();

foreach ($this->getMethods() as $method) {
foreach ($method->getParameters() as $parameter) {
if ($extendedClass && method_exists($extendedClass, $method->getName()) && $default = $parameter->getDefaultValue()) {
$parameter->setDefaultValue(new ValueGenerator($default, new ReflectionParameter([$extendedClass, $method->getName()], $parameter->getName())));
}
}
}

return parent::generate();
}
}
56 changes: 56 additions & 0 deletions src/ProxyManager/Generator/ValueGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace ProxyManager\Generator;

use Laminas\Code\Generator\ValueGenerator as LaminasValueGenerator;
use Laminas\Code\Generator\Exception\RuntimeException;
use UnitEnum;

use function is_array;

/**
* @internal do not use this in your code: it is only here for internal use
*/
class ValueGenerator extends LaminasValueGenerator
{
private $reflection;

public function __construct(LaminasValueGenerator $value, \ReflectionParameter $reflection)
{
foreach ($value as $k => $v) {
$this->$k = $v;
}

$this->reflection = $reflection;
}

public function generate(): string
{
if ($this->value instanceof UnitEnum) {
return self::export($this->value);
}

try {
return parent::generate();
} catch (RuntimeException $e) {
// FIXME: indentation and root namespace
return rtrim(substr(explode('$' . $this->reflection->name . ' = ', (string) $this->reflection, 2)[1], 0, -2));
}
}

public static function export($value): string
{
$value = var_export($value, true);
$parts = preg_split('{(\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')}', $value, -1, PREG_SPLIT_DELIM_CAPTURE);

foreach ($parts as $i => $part) {
if ($part !== '' && $i % 2 === 0) {
$parts[$i] = preg_replace('/(?(DEFINE)(?<V>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))(?&V)(?:\\\\(?&V))*+::/', '\\\\$0', $part);
}
}

return implode('', $parts);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@
use Laminas\Code\Generator\PropertyGenerator;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\Util\IdentifierSuffixer;
use ProxyManager\Generator\ValueGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionProperty;

use function array_map;
use function implode;
use function preg_replace;
use function preg_split;
use function sprintf;
use function str_replace;
use function var_export;

use const PREG_SPLIT_DELIM_CAPTURE;

/**
* Implementation for {@see \ProxyManager\Proxy\LazyLoadingInterface::isProxyInitialized}
* for lazy loading value holder objects
Expand Down Expand Up @@ -170,6 +175,15 @@ private function getExportedPropertyDefaultValue(ReflectionProperty $property):
$name = $property->getName();
$defaults = $property->getDeclaringClass()->getDefaultProperties();

return var_export($defaults[$name] ?? null, true);
$value = var_export($defaults[$name] ?? null, true);
$parts = preg_split('{(\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')}', $value, -1, PREG_SPLIT_DELIM_CAPTURE);

foreach ($parts as $i => $part) {
if ($part !== '' && $i % 2 === 0) {
$parts[$i] = preg_replace('/(?(DEFINE)(?<V>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))(?&V)(?:\\\\(?&V))*+::/', '\\\\$0', $part);
}
}

return implode('', $parts);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ class RemoteObjectMethod extends MethodGenerator
{
private const TEMPLATE
= <<<'PHP'
$defaultValues = #DEFAULT_VALUES#;
$declaredParameterCount = #PARAMETER_COUNT#;
static $reflection;
$args = \func_get_args() + $defaultValues;
$args = \func_get_args();
switch (\func_num_args()) {#DEFAULT_VALUES#
}
#PROXIED_RETURN#
PHP;
Expand All @@ -41,39 +43,36 @@ public static function generateMethod(
. ', ' . var_export($originalMethod->getName(), true) . ', $args);' . "\n\n"
. ProxiedMethodReturnExpression::generate('$return', $originalMethod);

$defaultValues = self::getDefaultValuesForMethod($originalMethod);
$declaredParameterCount = count($originalMethod->getParameters());
$defaultValues = self::getDefaultValuesForMethod($originalMethod);

$method->setBody(
strtr(
self::TEMPLATE,
[
'#PROXIED_RETURN#' => $proxiedReturn,
'#DEFAULT_VALUES#' => var_export($defaultValues, true),
'#PARAMETER_COUNT#' => var_export($declaredParameterCount, true),
'#DEFAULT_VALUES#' => $defaultValues,
]
)
);

return $method;
}

/** @psalm-return list<int|float|bool|array|string|null> */
private static function getDefaultValuesForMethod(MethodReflection $originalMethod): array
private static function getDefaultValuesForMethod(MethodReflection $originalMethod): string
{
$defaultValues = [];
foreach ($originalMethod->getParameters() as $parameter) {
$parameters = sprintf('($reflection ?? $reflection = (new \ReflectionMethod(\'%s\', \'%s\'))->getParameters())', $originalMethod->class, $originalMethod->name);
$defaultValues = '';
foreach ($originalMethod->getParameters() as $i => $parameter) {
if ($parameter->isOptional() && $parameter->isDefaultValueAvailable()) {
/** @psalm-var int|float|bool|array|string|null */
$defaultValues[] = $parameter->getDefaultValue();
$defaultValues .= "\n case $i: \$args[] = {$parameters}[$i]->getDefaultValue();";
continue;
}

if ($parameter->isVariadic()) {
continue;
}

$defaultValues[] = null;
$defaultValues .= "\n case $i: \$args[] = NULL;";
}

return $defaultValues;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace ProxyManagerTest\Functional;

use Laminas\Code\Generator\ClassGenerator;
use PHPUnit\Framework\TestCase;
use ProxyManager\Exception\ExceptionInterface;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
use ProxyManager\Proxy\ProxyInterface;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizerGenerator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use ProxyManagerTestAsset\ClassWithMixedTypedProperties;
use ProxyManagerTestAsset\ClassWithParentHint;
use ProxyManagerTestAsset\ClassWithPhp80TypedMethods;
use ProxyManagerTestAsset\ClassWithPhp81Defaults;
use ProxyManagerTestAsset\ClassWithPrivateProperties;
use ProxyManagerTestAsset\ClassWithProtectedProperties;
use ProxyManagerTestAsset\ClassWithPublicProperties;
Expand Down Expand Up @@ -138,6 +139,10 @@ public function getTestedClasses(): array
$objects[] = [new ClassWithPhp80TypedMethods()];
}

if (PHP_VERSION_ID >= 80100) {
$objects['php81defaults'] = [new ClassWithPhp81Defaults()];
}

return $objects;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace ProxyManagerTest\GeneratorStrategy;

use Laminas\Code\Generator\ClassGenerator;
use PHPUnit\Framework\TestCase;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\GeneratorStrategy\BaseGeneratorStrategy;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace ProxyManagerTest\GeneratorStrategy;

use Laminas\Code\Generator\ClassGenerator;
use PHPUnit\Framework\TestCase;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

namespace ProxyManagerTest\GeneratorStrategy;

use Laminas\Code\Generator\ClassGenerator;
use PHPUnit\Framework\TestCase;
use ProxyManager\Exception\FileNotWritableException;
use ProxyManager\FileLocator\FileLocatorInterface;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace ProxyManagerTest\ProxyGenerator;

use Laminas\Code\Generator\ClassGenerator;
use PHPUnit\Framework\TestCase;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
Expand All @@ -18,6 +18,7 @@
use ProxyManagerTestAsset\ClassWithMixedReferenceableTypedProperties;
use ProxyManagerTestAsset\ClassWithMixedTypedProperties;
use ProxyManagerTestAsset\ClassWithPhp80TypedMethods;
use ProxyManagerTestAsset\ClassWithPhp81Defaults;
use ProxyManagerTestAsset\IterableMethodTypeHintedInterface;
use ProxyManagerTestAsset\ObjectMethodTypeHintedInterface;
use ProxyManagerTestAsset\ReturnTypeHintedClass;
Expand Down Expand Up @@ -112,6 +113,10 @@ public function getTestedImplementations(): array
$implementations[] = [ClassWithPhp80TypedMethods::class];
}

if (PHP_VERSION_ID >= 80100) {
$implementations['php81defaults'] = [ClassWithPhp81Defaults::class];
}

return $implementations;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace ProxyManagerTest\ProxyGenerator;

use Laminas\Code\Generator\ClassGenerator;
use ProxyManager\Exception\InvalidProxiedClassException;
use ProxyManager\Exception\UnsupportedProxiedClassException;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\Proxy\AccessInterceptorInterface;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizerGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace ProxyManagerTest\ProxyGenerator;

use Laminas\Code\Generator\ClassGenerator;
use ProxyManager\Exception\InvalidProxiedClassException;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\Proxy\GhostObjectInterface;
use ProxyManager\ProxyGenerator\LazyLoadingGhostGenerator;
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace ProxyManagerTest\ProxyGenerator;

use Laminas\Code\Generator\ClassGenerator;
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
use ProxyManager\Proxy\NullObjectInterface;
Expand All @@ -19,6 +19,7 @@
use ProxyManagerTestAsset\ClassWithMixedReferenceableTypedProperties;
use ProxyManagerTestAsset\ClassWithMixedTypedProperties;
use ProxyManagerTestAsset\ClassWithPhp80TypedMethods;
use ProxyManagerTestAsset\ClassWithPhp81Defaults;
use ReflectionClass;
use ReflectionMethod;

Expand Down Expand Up @@ -131,6 +132,10 @@ public function getTestedImplementations(): array
$implementations[] = [ClassWithPhp80TypedMethods::class];
}

if (PHP_VERSION_ID >= 80100) {
$implementations[] = [ClassWithPhp81Defaults::class];
}

return $implementations;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ public function testBodyStructureWithParameters(): void
self::assertSame('publicByReferenceParameterMethod', $method->getName());
self::assertCount(2, $method->getParameters());
self::assertSame(
'$defaultValues = array (
0 => NULL,
1 => NULL,
);
$declaredParameterCount = 2;
'static $reflection;
$args = \func_get_args() + $defaultValues;
$args = \func_get_args();
switch (\func_num_args()) {
case 0: $args[] = NULL;
case 1: $args[] = NULL;
}
$return = $this->adapter->call(\'Laminas\\\\Code\\\\Generator\\\\PropertyGenerator\', \'publicByReferenceParameterMethod\', $args);
Expand Down Expand Up @@ -74,12 +75,13 @@ public function testBodyStructureWithArrayParameter(): void
self::assertSame('publicArrayHintedMethod', $method->getName());
self::assertCount(1, $method->getParameters());
self::assertSame(
"\$defaultValues = array (
0 => NULL,
);
\$declaredParameterCount = 1;
"static \$reflection;
\$args = \\func_get_args();
\$args = \\func_get_args() + \$defaultValues;
switch (\\func_num_args()) {
case 0: \$args[] = NULL;
}
\$return = \$this->adapter->call('Laminas\\\\Code\\\\Generator\\\\PropertyGenerator', 'publicArrayHintedMethod', \$args);
Expand Down Expand Up @@ -107,11 +109,12 @@ public function testBodyStructureWithoutParameters(): void
self::assertSame('publicMethod', $method->getName());
self::assertCount(0, $method->getParameters());
self::assertSame(
"\$defaultValues = array (
);
\$declaredParameterCount = 0;
"static \$reflection;
\$args = \\func_get_args();
\$args = \\func_get_args() + \$defaultValues;
switch (\\func_num_args()) {
}
\$return = \$this->adapter->call('Laminas\\\\Code\\\\Generator\\\\PropertyGenerator', 'publicMethod', \$args);
Expand Down
Loading

0 comments on commit 38fe500

Please sign in to comment.