Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,428 changes: 739 additions & 689 deletions docs/bootstrap-inventory.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions lib/Func/PHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use PHPCompiler\Compiler\AttributeEntry;
use PHPCompiler\Compiler\DeprecatedMetadata;
use PHPCompiler\Compiler\SourceLocation;
use PHPCompiler\Func;
use PHPCompiler\Frame;
use PHPCompiler\Block;
Expand All @@ -21,6 +22,8 @@ final class PHP extends Func {
public Block $block;
/** #[\Deprecated] metadata when declared on this function/method (#3569). */
public ?DeprecatedMetadata $deprecated = null;
/** Compile-time docblock + declaration site for ReflectionFunction (#22144 / #7358). */
public ?SourceLocation $sourceLocation = null;
/** @var list<\PHPCompiler\Compiler\ParameterMetadata> */
public array $parameterMetadata = [];
/** @var list<string> */
Expand Down
2 changes: 2 additions & 0 deletions lib/VM.php
Original file line number Diff line number Diff line change
Expand Up @@ -5541,6 +5541,7 @@ private function runFramesInner(): int
? $op->block1->func->name
: '{closure}';
$closureFunc = new Func\PHP($funcName, $op->block1);
$closureFunc->sourceLocation = $op->sourceLocation;
if ([] !== $op->parameterMetadata) {
$closureFunc->parameterMetadata = $op->parameterMetadata;
}
Expand Down Expand Up @@ -5622,6 +5623,7 @@ private function runFramesInner(): int
throw new \LogicException("Duplicate function definition for $lcname()");
}
$func = new Func\PHP($name, $op->block1);
$func->sourceLocation = $op->sourceLocation;
$func->deprecated = $op->deprecatedMetadata;
if ([] !== $op->parameterMetadata) {
$func->parameterMetadata = $op->parameterMetadata;
Expand Down
34 changes: 34 additions & 0 deletions lib/VM/Builtin/ReflectionFunctionGetDocComment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\VM\Builtin;

use PHPCompiler\ext\standard\VmReflection;
use PHPCompiler\Frame;
use PHPCompiler\VM\ReflectionSupport;

/** ReflectionFunction::getDocComment() — VM (#22144, ext/reflection/php_reflection.c). */
final class ReflectionFunctionGetDocComment extends VmClassMethod
{
public function __construct()
{
parent::__construct('getDocComment');
}

public function execute(Frame $frame): void
{
$ctx = VmReflection::requireContext($frame);
$receiver = ReflectionSupport::requireReflectionFunction($frame, $frame->calledArgs[0]);
if (null === $frame->returnVar) {
return;
}
if (ReflectionSupport::isReflectionInternalFunction($receiver)) {
$frame->returnVar->bool(false);

return;
}
$loc = ReflectionSupport::functionSourceLocation($ctx, $receiver);
ReflectionSupport::returnDocComment($frame->returnVar, $loc?->docComment);
}
}
29 changes: 29 additions & 0 deletions lib/VM/Builtin/ReflectionFunctionGetEndLine.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\VM\Builtin;

use PHPCompiler\ext\standard\VmReflection;
use PHPCompiler\Frame;
use PHPCompiler\VM\ReflectionSupport;

/** ReflectionFunction::getEndLine() — VM (#22144, ext/reflection/php_reflection.c). */
final class ReflectionFunctionGetEndLine extends VmClassMethod
{
public function __construct()
{
parent::__construct('getEndLine');
}

public function execute(Frame $frame): void
{
$ctx = VmReflection::requireContext($frame);
$receiver = ReflectionSupport::requireReflectionFunction($frame, $frame->calledArgs[0]);
ReflectionSupport::returnFunctionEndLine(
$frame->returnVar,
ReflectionSupport::functionSourceLocation($ctx, $receiver),
ReflectionSupport::isReflectionInternalFunction($receiver)
);
}
}
29 changes: 29 additions & 0 deletions lib/VM/Builtin/ReflectionFunctionGetFileName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\VM\Builtin;

use PHPCompiler\ext\standard\VmReflection;
use PHPCompiler\Frame;
use PHPCompiler\VM\ReflectionSupport;

/** ReflectionFunction::getFileName() — VM (#22144, ext/reflection/php_reflection.c). */
final class ReflectionFunctionGetFileName extends VmClassMethod
{
public function __construct()
{
parent::__construct('getFileName');
}

public function execute(Frame $frame): void
{
$ctx = VmReflection::requireContext($frame);
$receiver = ReflectionSupport::requireReflectionFunction($frame, $frame->calledArgs[0]);
ReflectionSupport::returnFunctionFileName(
$frame->returnVar,
ReflectionSupport::functionSourceLocation($ctx, $receiver),
ReflectionSupport::isReflectionInternalFunction($receiver)
);
}
}
25 changes: 25 additions & 0 deletions lib/VM/Builtin/ReflectionFunctionGetNamespaceName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\VM\Builtin;

use PHPCompiler\Frame;
use PHPCompiler\VM\ReflectionSupport;

/** ReflectionFunction::getNamespaceName() — VM (#22144, ext/reflection/php_reflection.c). */
final class ReflectionFunctionGetNamespaceName extends VmClassMethod
{
public function __construct()
{
parent::__construct('getNamespaceName');
}

public function execute(Frame $frame): void
{
$receiver = ReflectionSupport::requireReflectionFunction($frame, $frame->calledArgs[0]);
if (null !== $frame->returnVar) {
$frame->returnVar->string(ReflectionSupport::functionNamespaceNameFromReflection($receiver));
}
}
}
25 changes: 25 additions & 0 deletions lib/VM/Builtin/ReflectionFunctionGetShortName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\VM\Builtin;

use PHPCompiler\Frame;
use PHPCompiler\VM\ReflectionSupport;

/** ReflectionFunction::getShortName() — VM (#22144, ext/reflection/php_reflection.c). */
final class ReflectionFunctionGetShortName extends VmClassMethod
{
public function __construct()
{
parent::__construct('getShortName');
}

public function execute(Frame $frame): void
{
$receiver = ReflectionSupport::requireReflectionFunction($frame, $frame->calledArgs[0]);
if (null !== $frame->returnVar) {
$frame->returnVar->string(ReflectionSupport::functionShortNameFromReflection($receiver));
}
}
}
29 changes: 29 additions & 0 deletions lib/VM/Builtin/ReflectionFunctionGetStartLine.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\VM\Builtin;

use PHPCompiler\ext\standard\VmReflection;
use PHPCompiler\Frame;
use PHPCompiler\VM\ReflectionSupport;

/** ReflectionFunction::getStartLine() — VM (#22144, ext/reflection/php_reflection.c). */
final class ReflectionFunctionGetStartLine extends VmClassMethod
{
public function __construct()
{
parent::__construct('getStartLine');
}

public function execute(Frame $frame): void
{
$ctx = VmReflection::requireContext($frame);
$receiver = ReflectionSupport::requireReflectionFunction($frame, $frame->calledArgs[0]);
ReflectionSupport::returnFunctionStartLine(
$frame->returnVar,
ReflectionSupport::functionSourceLocation($ctx, $receiver),
ReflectionSupport::isReflectionInternalFunction($receiver)
);
}
}
25 changes: 25 additions & 0 deletions lib/VM/Builtin/ReflectionFunctionInNamespace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\VM\Builtin;

use PHPCompiler\Frame;
use PHPCompiler\VM\ReflectionSupport;

/** ReflectionFunction::inNamespace() — VM (#22144, ext/reflection/php_reflection.c). */
final class ReflectionFunctionInNamespace extends VmClassMethod
{
public function __construct()
{
parent::__construct('inNamespace');
}

public function execute(Frame $frame): void
{
$receiver = ReflectionSupport::requireReflectionFunction($frame, $frame->calledArgs[0]);
if (null !== $frame->returnVar) {
$frame->returnVar->bool(ReflectionSupport::functionInNamespaceFromReflection($receiver));
}
}
}
14 changes: 14 additions & 0 deletions lib/VM/BuiltinClasses.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,13 @@
use PHPCompiler\VM\Builtin\ReflectionFunctionGetAttributes;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetExtension;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetExtensionName;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetFileName;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetDocComment;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetEndLine;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetStartLine;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetNamespaceName;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetShortName;
use PHPCompiler\VM\Builtin\ReflectionFunctionInNamespace;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetName;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetNamedArguments;
use PHPCompiler\VM\Builtin\ReflectionFunctionGetNumberOfParameters;
Expand Down Expand Up @@ -1095,6 +1102,13 @@ private static function registerReflection(Context $ctx): void
'isvariadic' => new ReflectionFunctionIsVariadic(),
'getextensionname' => new ReflectionFunctionGetExtensionName(),
'getextension' => new ReflectionFunctionGetExtension(),
'getfilename' => new ReflectionFunctionGetFileName(),
'getdoccomment' => new ReflectionFunctionGetDocComment(),
'getstartline' => new ReflectionFunctionGetStartLine(),
'getendline' => new ReflectionFunctionGetEndLine(),
'getnamespacename' => new ReflectionFunctionGetNamespaceName(),
'getshortname' => new ReflectionFunctionGetShortName(),
'innamespace' => new ReflectionFunctionInNamespace(),
'getclosurethis' => new ReflectionFunctionGetClosureThis(),
'getclosure' => new ReflectionFunctionGetClosure(),
'getclosurescopeclass' => new ReflectionFunctionGetClosureScopeClass(),
Expand Down
121 changes: 121 additions & 0 deletions lib/VM/ReflectionSupport.php
Original file line number Diff line number Diff line change
Expand Up @@ -2722,6 +2722,127 @@ public static function methodSourceLocation(ClassEntry $entry, string $methodLc)
return $entry->methodSourceLocations[$methodLc] ?? null;
}

/**
* ReflectionFunction source metadata — Func\PHP::$sourceLocation or ClosureState (#22144).
*/
public static function functionSourceLocation(Context $ctx, ObjectEntry $reflection): ?SourceLocation
{
$state = $reflection->reflectionClosureState;
if (null !== $state) {
$func = $state->func;
if ($func instanceof Func\PHP && null !== $func->sourceLocation) {
return $func->sourceLocation;
}
if ('' !== $state->definitionFile || $state->definitionLine > 0) {
return new SourceLocation(
null,
$state->definitionLine,
$state->definitionLine,
$state->definitionFile
);
}

return null;
}
if ($reflection->reflectionIsInternalFunction) {
return null;
}
$name = self::functionNameFromReflection($reflection);
$func = $ctx->functions[strtolower($name)] ?? null;
if ($func instanceof Func\PHP) {
return $func->sourceLocation;
}

return null;
}

/**
* ReflectionFunction::getShortName() — php-src suffix after last backslash; closures → {closure} (#22144).
*/
public static function functionShortNameFromReflection(ObjectEntry $reflection): string
{
$state = $reflection->reflectionClosureState;
if (null !== $state && $state->isUserClosure()) {
return '{closure}';
}

return self::globalConstantShortName(self::functionNameFromReflection($reflection));
}

/**
* ReflectionFunction::getNamespaceName() — php-src prefix before last backslash (#22144).
*/
public static function functionNamespaceNameFromReflection(ObjectEntry $reflection): string
{
$state = $reflection->reflectionClosureState;
if (null !== $state && $state->isUserClosure()) {
// Named display is {anonymous}#N without NS; Zend uses declaring namespace.
// Prefer Func name when it is Demo\{closure}-shaped; else empty until tracked.
$name = $state->func->getName();
if (str_contains($name, '\\')) {
return self::globalConstantNamespaceName($name);
}

return '';
}

return self::globalConstantNamespaceName(self::functionNameFromReflection($reflection));
}

/** ReflectionFunction::inNamespace() — php-src (#22144). */
public static function functionInNamespaceFromReflection(ObjectEntry $reflection): bool
{
return '' !== self::functionNamespaceNameFromReflection($reflection);
}

/**
* ReflectionFunction::{getFileName,getStartLine,getEndLine} — false for internals / missing (#22144).
*/
public static function returnFunctionFileName(?Variable $returnVar, ?SourceLocation $location, bool $isInternal): void
{
if (null === $returnVar) {
return;
}
if ($isInternal || null === $location) {
$returnVar->bool(false);

return;
}
$file = $location->filename;
if ('' === $file || 'unknown' === $file) {
$returnVar->bool(false);

return;
}
$returnVar->string($file);
}

public static function returnFunctionStartLine(?Variable $returnVar, ?SourceLocation $location, bool $isInternal): void
{
if (null === $returnVar) {
return;
}
if ($isInternal || null === $location || $location->startLine <= 0) {
$returnVar->bool(false);

return;
}
$returnVar->int($location->startLine);
}

public static function returnFunctionEndLine(?Variable $returnVar, ?SourceLocation $location, bool $isInternal): void
{
if (null === $returnVar) {
return;
}
if ($isInternal || null === $location || $location->endLine <= 0) {
$returnVar->bool(false);

return;
}
$returnVar->int($location->endLine);
}

public static function propertySourceLocation(Context $ctx, ClassEntry $entry, string $property): ?SourceLocation
{
$lc = strtolower($property);
Expand Down
2 changes: 1 addition & 1 deletion prelinked/bootstrap-gen0/.bootstrap_lowering_source.sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
bad85658802e26cc4d82f8982208ad5d4f8ebaa472a20405e0dbc264116b27ec
d2903f20d992e1d2964b512eb44b5ca36f713cd12f9fedb62b1440097e30af52
Loading
Loading