Skip to content

Commit

Permalink
Fix exporting default values on PHP 8.2/8.1
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Oct 17, 2022
1 parent 5ca79bc commit 8835461
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 9 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
pull_request:
push:

defaults:
run:
shell: bash

jobs:
phpunit:
name: "PHPUnit tests"
Expand All @@ -19,8 +23,10 @@ jobs:
- "7.4"
- "8.0"
- "8.1"
- "8.2"
operating-system:
- "ubuntu-latest"
fail-fast: false

steps:
- name: "Checkout"
Expand All @@ -44,7 +50,10 @@ jobs:
restore-keys: "php-${{ matrix.php-version }}"

- name: "Test with lowest dependencies"
run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest && vendor/bin/simple-phpunit"
if: "matrix.php-version != '8.2'"
run: |
composer update --prefer-lowest --no-interaction --no-progress --no-suggest && vendor/bin/simple-phpunit
- name: "Test with highest dependencies"
run: "composer update --no-interaction --no-progress --no-suggest && vendor/bin/simple-phpunit"
run: |
composer update --no-interaction --no-progress --no-suggest $([[ "${{ matrix.php-version }}" = "8.2" ]] && echo ' --ignore-platform-req=php+') && vendor/bin/simple-phpunit
55 changes: 52 additions & 3 deletions src/ProxyManager/Generator/ValueGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@

use function explode;
use function implode;
use function in_array;
use function preg_replace;
use function preg_split;
use function rtrim;
use function substr;
use function var_export;

use const PREG_SPLIT_DELIM_CAPTURE;
use const PREG_SPLIT_NO_EMPTY;

/**
* @internal do not use this in your code: it is only here for internal use
Expand Down Expand Up @@ -50,16 +52,20 @@ public function generate(): string
return parent::generate();
} catch (RuntimeException $e) {
if ($this->reflection) {
$value = rtrim(substr(explode('$' . $this->reflection->getName() . ' = ', (string) $this->reflection, 2)[1], 0, -2));
$value = self::exportDefault($this->reflection);
} else {
$value = var_export($this->value, true);

if (\PHP_VERSION_ID < 80200) {
return self::fixVarExport($value);
}
}

return self::fixExport($value);
return $value;
}
}

private static function fixExport(string $value): string
private static function fixVarExport(string $value): string
{
$parts = preg_split('{(\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')}', $value, -1, PREG_SPLIT_DELIM_CAPTURE);

Expand All @@ -73,4 +79,47 @@ private static function fixExport(string $value): string

return implode('', $parts);
}

private static function exportDefault(\ReflectionParameter $param): string
{
$default = rtrim(substr(explode('$'.$param->name.' = ', (string) $param, 2)[1] ?? '', 0, -2));

if (in_array($default, ['<default>', 'NULL'], true)) {
return 'null';
}
if (str_ends_with($default, "...'") && preg_match("/^'(?:[^'\\\\]*+(?:\\\\.)*+)*+'$/", $default)) {
return var_export($param->getDefaultValue(), true);
}

$regexp = "/(\"(?:[^\"\\\\]*+(?:\\\\.)*+)*+\"|'(?:[^'\\\\]*+(?:\\\\.)*+)*+')/";
$parts = preg_split($regexp, $default, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

$regexp = '/([\[\( ]|^)([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z0-9_\x7f-\xff]++)*+)(?!: )/';
$callback = (false !== strpbrk($default, "\\:('") && $class = $param->getDeclaringClass())
? function ($m) use ($class) {
switch ($m[2]) {
case 'new': case 'false': case 'true': case 'null': return $m[1].$m[2];
case 'NULL': return $m[1].'null';
case 'self': return $m[1].'\\'.$class->name;
case 'namespace\\parent':
case 'parent': $m[1].(($parent = $class->getParentClass()) ? '\\'.$parent->name : 'parent');
default: return $m[1].'\\'.$m[2];
}
}
: function ($m) {
switch ($m[2]) {
case 'new': case 'false': case 'true': case 'null': return $m[1].$m[2];
case 'NULL': return $m[1].'null';
default: return $m[1].'\\'.$m[2];
}
};

return implode('', array_map(function ($part) use ($regexp, $callback) {
switch ($part[0]) {
case '"': return $part; // for internal classes only
case "'": return false !== strpbrk($part, "\\\0\r\n") ? '"'.substr(str_replace(['$', "\0", "\r", "\n"], ['\$', '\0', '\r', '\n'], $part), 1, -1).'"' : $part;
default: return preg_replace_callback($regexp, $callback, $part);
}
}, $parts));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Verifies that generated lazy loading ghost objects disallow reading non-existing

require_once __DIR__ . '/init.php';

#[AllowDynamicProperties]
class Kitchen
{
private $sweets;
Expand All @@ -22,4 +23,4 @@ $proxy = $factory->createProxy(Kitchen::class, function () {});
echo $proxy->nonExisting;
?>
--EXPECTF--
nonExisting
nonExisting
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Verifies that generated lazy loading ghost objects disallow reading non-existing

require_once __DIR__ . '/init.php';

#[AllowDynamicProperties]
class Kitchen
{
private $sweets;
Expand All @@ -18,4 +19,4 @@ $proxy->nonExisting = 'I do not exist';
echo $proxy->nonExisting;
?>
--EXPECTF--
I do not exist
I do not exist
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Verifies that generated lazy loading ghost objects disallow reading non-existing

require_once __DIR__ . '/init.php';

#[AllowDynamicProperties]
class Kitchen
{
private $sweets;
Expand All @@ -17,4 +18,4 @@ $proxy = $factory->createProxy(Kitchen::class, function () {});
$proxy->nonExisting;
?>
--EXPECTF--
%SNotice: Undefined property: Kitchen::$nonExisting in %a
%SNotice: Undefined property: Kitchen::$nonExisting in %a
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Verifies that generated lazy loading ghost objects can skip calling the proxied

require_once __DIR__ . '/init.php';

#[AllowDynamicProperties]
class Destructable
{
public function __destruct()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ $factory = new \ProxyManager\Factory\LazyLoadingValueHolderFactory($configuratio
$proxy = $factory
->createProxy(MyInterface::class, function (& $wrapped, $proxy, $method, array $parameters, & $initializer) : bool {
$initializer = null;
$wrapped = new class implements MyInterface {
$wrapped = new #[AllowDynamicProperties]
class implements MyInterface {
};

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface MyInterface
public function do();
}

#[AllowDynamicProperties]
class MyClass implements MyInterface
{
public function do()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Verifies that generated lazy loading value holders can skip calling the proxied

require_once __DIR__ . '/init.php';

#[AllowDynamicProperties]
class Destructable
{
public function __destruct()
Expand Down

0 comments on commit 8835461

Please sign in to comment.