- Updated resolveAnonClassTypeNames to resolveAnonClassNames with improved name resolution - Added proper handling of imported names in anonymous class method bodies - Ensured fully qualified names are embedded when anonymous classes are evaluated - Added test case for anonymous class method bodies preserving namespace imports - Fixed function call trait to check global name instead of local name for unsupported functions - Added tests for destructor exception handling boundaries - Improved include error handling and shutdown exception handler behavior - Added unsupported function detection for extract function with proper error messages - Updated swoole/phpx dependency from ~2.5.3 to ~2.5.5pull/48/head
parent
5fb3fdf490
commit
a79610fb2c
12 changed files with 228 additions and 10 deletions
@ -0,0 +1,8 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace App; |
||||||
|
|
||||||
|
function importVariables(array $values): void |
||||||
|
{ |
||||||
|
\extract($values); |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
function importVariables(array $values): void |
||||||
|
{ |
||||||
|
extract($values); |
||||||
|
} |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
class UnsupportedFunctionTest extends BaseTest |
||||||
|
{ |
||||||
|
public function testExtractIsRejectedAtCompileTime(): void |
||||||
|
{ |
||||||
|
$this->exec('Unsupported function: `extract`', 'unsupported-function-extract.php'); |
||||||
|
} |
||||||
|
|
||||||
|
public function testFullyQualifiedExtractIsRejectedAtCompileTime(): void |
||||||
|
{ |
||||||
|
$this->exec('Unsupported function: `extract`', 'unsupported-function-extract-qualified.php'); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,49 @@ |
|||||||
|
--TEST-- |
||||||
|
Anonymous class method bodies preserve namespace imports |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
namespace AnonymousClassSupport { |
||||||
|
const FLAG = 'imported'; |
||||||
|
|
||||||
|
class Subject {} |
||||||
|
|
||||||
|
class Marker { |
||||||
|
public const string VALUE = 'resolved'; |
||||||
|
} |
||||||
|
|
||||||
|
function accepts(Subject $value): bool { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
namespace AnonymousClassConsumer { |
||||||
|
use AnonymousClassSupport\Marker as ImportedMarker; |
||||||
|
use AnonymousClassSupport\Subject as ImportedSubject; |
||||||
|
use const AnonymousClassSupport\FLAG as IMPORTED_FLAG; |
||||||
|
use function AnonymousClassSupport\accepts as imported_accepts; |
||||||
|
|
||||||
|
function main(): void { |
||||||
|
$visitor = new class('ready') { |
||||||
|
public function __construct(private readonly string $state) {} |
||||||
|
|
||||||
|
public function accepts(object $value): bool { |
||||||
|
return $value instanceof ImportedSubject |
||||||
|
&& ImportedMarker::VALUE === 'resolved' |
||||||
|
&& IMPORTED_FLAG === 'imported' |
||||||
|
&& imported_accepts($value) |
||||||
|
&& $this->state === 'ready'; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
var_dump($visitor->accepts(new ImportedSubject())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
namespace { |
||||||
|
function main(): void { |
||||||
|
AnonymousClassConsumer\main(); |
||||||
|
} |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
bool(true) |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
--TEST-- |
||||||
|
TypePHP destructor exceptions remain inside the Zend wrapper boundary |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
final class ThrowingDestructor |
||||||
|
{ |
||||||
|
public function __destruct() |
||||||
|
{ |
||||||
|
throw new RuntimeException('destructor'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
try { |
||||||
|
$value = new ThrowingDestructor(); |
||||||
|
unset($value); |
||||||
|
} catch (RuntimeException $exception) { |
||||||
|
echo $exception->getMessage(), "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
echo "continued\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
destructor |
||||||
|
continued |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
--TEST-- |
||||||
|
An exception handler may include a PHP file during shutdown |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function handleShutdownException(Throwable $exception): void |
||||||
|
{ |
||||||
|
global $shutdownState; |
||||||
|
|
||||||
|
echo 'state:', $shutdownState, "\n"; |
||||||
|
echo 'handled:', $exception->getMessage(), "\n"; |
||||||
|
|
||||||
|
$file = tempnam(sys_get_temp_dir(), 'typephp-shutdown-'); |
||||||
|
file_put_contents($file, '<?php echo "included during shutdown\\n";'); |
||||||
|
include $file; |
||||||
|
unlink($file); |
||||||
|
} |
||||||
|
|
||||||
|
function throwDuringShutdown(): void |
||||||
|
{ |
||||||
|
throw new RuntimeException('shutdown failure'); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
global $shutdownState; |
||||||
|
|
||||||
|
$shutdownState = 'request alive'; |
||||||
|
set_exception_handler('handleShutdownException'); |
||||||
|
register_shutdown_function('throwDuringShutdown'); |
||||||
|
echo "main completed\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
main completed |
||||||
|
state:request alive |
||||||
|
handled:shutdown failure |
||||||
|
included during shutdown |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
--TEST-- |
||||||
|
An exception from an error handler unwinds an included PHP frame safely |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function throwIncludeWarning(int $severity, string $message, string $file, int $line): never |
||||||
|
{ |
||||||
|
throw new ErrorException($message, 0, $severity, $file, $line); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$file = tempnam(sys_get_temp_dir(), 'typephp-include-unwind-'); |
||||||
|
file_put_contents($file, '<?php echo $undefinedIncludeVariable;'); |
||||||
|
set_error_handler('throwIncludeWarning'); |
||||||
|
|
||||||
|
try { |
||||||
|
include $file; |
||||||
|
} catch (ErrorException $exception) { |
||||||
|
echo str_contains($exception->getMessage(), 'undefinedIncludeVariable') ? "caught\n" : "wrong exception\n"; |
||||||
|
} finally { |
||||||
|
restore_error_handler(); |
||||||
|
unlink($file); |
||||||
|
} |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
caught |
||||||
Loading…
Reference in new issue