0 follower

Final Class Yiisoft\VarDumper\ClosureExporter

InheritanceYiisoft\VarDumper\ClosureExporter

ClosureExporter exports PHP {@see \Closure} as a string containing PHP code.

The string is a valid PHP expression that can be evaluated by PHP parser and the evaluation result will give back the closure instance.

Public Methods

Hide inherited methods

Method Description Defined By
__construct() Yiisoft\VarDumper\ClosureExporter
export() Export closure as a string containing PHP code. Yiisoft\VarDumper\ClosureExporter

Method Details

Hide inherited methods

__construct() public method

public mixed __construct ( )

                public function __construct()
{
    $this->useStatementParser = new UseStatementParser();
}

            
export() public method

Export closure as a string containing PHP code.

public string export ( Closure $closure, integer $level 0 )
$closure Closure

Closure to export.

$level integer

Level for padding.

return string

String containing PHP code.

throws ReflectionException

                public function export(Closure $closure, int $level = 0): string
{
    $reflection = new ReflectionFunction($closure);
    $fileName = $reflection->getFileName();
    $start = $reflection->getStartLine();
    $end = $reflection->getEndLine();
    if ($fileName === false || $start === false || $end === false || ($fileContent = file($fileName)) === false) {
        return 'function () {/* Error: unable to determine Closure source */}';
    }
    --$start;
    $uses = $this->useStatementParser->fromFile($fileName);
    $tokens = token_get_all('<?php ' . implode('', array_slice($fileContent, $start, $end - $start)));
    array_shift($tokens);
    $bufferUse = '';
    $closureTokens = [];
    $pendingParenthesisCount = 0;
    /** @var int<1, max> $i */
    foreach ($tokens as $i => $token) {
        if (in_array($token[0], [T_FUNCTION, T_FN, T_STATIC], true)) {
            $closureTokens[] = $token[1];
            continue;
        }
        if ($closureTokens === []) {
            continue;
        }
        $readableToken = is_array($token) ? $token[1] : $token;
        if ($this->useStatementParser->isTokenIsPartOfUse($token)) {
            if ($this->isUseConsistingOfMultipleParts($readableToken)) {
                $readableToken = $this->processFullUse($readableToken, $uses);
                $bufferUse = '';
            } elseif (isset($uses[$readableToken])) {
                if (isset($tokens[$i + 1]) && $this->useStatementParser->isTokenIsPartOfUse($tokens[$i + 1])) {
                    $bufferUse .= $uses[$readableToken];
                    continue;
                }
                $readableToken = $uses[$readableToken];
            } elseif ($readableToken === '\\' && isset($tokens[$i - 1][1]) && $tokens[$i - 1][1] === '\\') {
                continue;
            } elseif (isset($tokens[$i + 1]) && $this->useStatementParser->isTokenIsPartOfUse($tokens[$i + 1])) {
                $bufferUse .= $readableToken;
                continue;
            }
            if (!empty($bufferUse)) {
                if ($bufferUse !== $readableToken && !str_contains($readableToken, $bufferUse)) {
                    $readableToken = $bufferUse . $readableToken;
                }
                $bufferUse = '';
            }
        }
        if (is_string($token)) {
            if ($this->isOpenParenthesis($token)) {
                $pendingParenthesisCount++;
            } elseif ($this->isCloseParenthesis($token)) {
                if ($pendingParenthesisCount === 0) {
                    break;
                }
                --$pendingParenthesisCount;
            } elseif ($token === ',' || $token === ';') {
                if ($pendingParenthesisCount === 0) {
                    break;
                }
            }
        }
        $closureTokens[] = $readableToken;
    }
    return $this->formatClosure(implode('', $closureTokens), $level);
}