programing

PHP 함수의 소스 코드 재구성/가져오기

projobs 2022. 10. 2. 15:16
반응형

PHP 함수의 소스 코드 재구성/가져오기

함수의 소스 코드를 이름으로 프로그래밍 방식으로 가져올 수 있습니까?

예를 들어 다음과 같습니다.

function blah($a, $b) { return $a*$b; }
echo getFunctionCode("blah");

가능합니까?

함수/클래스 코드를 재구성하기 위한 php 자기 기술 함수가 있습니까?(소스 파일에서 바로 소스 코드를 가져오는 대신)

Java에는 http://java.sun.com/developer/technicalArticles/ALT/Reflection/ 가 있습니다.

Reflection을 사용하기 위한 제안을 확장합니다.다음과 같은 기능을 사용할 수 있습니다.

$func = new ReflectionFunction('myfunction');
$filename = $func->getFileName();
$start_line = $func->getStartLine() - 1; // it's actually - 1, otherwise you wont get the function() block
$end_line = $func->getEndLine();
$length = $end_line - $start_line;

$source = file($filename);
$body = implode("", array_slice($source, $start_line, $length));
print_r($body);

함수의 실제 코드를 알려줄 수 있는 것은 없습니다.이용 가능한 것은 Reflection뿐입니다.함수 클래스클래스의 경우 클래스 멤버(상수, 변수 및 메서드)와 가시성을 제공하는 ReflectionClass가 있지만 실제 코드는 없습니다.


회피책(소스 파일 읽기 포함):
리플렉션 사용Function:: export를 통해 함수가 선언된 파일 이름과 행 간격을 확인한 후 해당 행의 파일 내용을 읽습니다.문자열 처리를 사용하여 첫 번째 항목 사이의 값을 가져옵니다.{ 마지막 '마지막'은}.

리플렉션 API: 리플렉션 API입니다. ReflectionFunction::export7.4PHP 7.4에서 되지 않습니다.

다른 운영체제(gnu/linux, windows, mac...)를 사용하여 프로그래밍합니다.이 때문에 코드에 캐리지 리턴이 다르기 때문에 이를 해결하기 위해 Brandon Horsley의 답변을 포크하여 다른 CR을 확인하고 함수 대신 클래스의 메서드에서 코드를 얻을 준비를 했습니다.

$cn = 'class_example';
$method = 'method_example';

$func = new ReflectionMethod($cn, $method);

$f = $func->getFileName();
$start_line = $func->getStartLine() - 1;
$end_line = $func->getEndLine();
$length = $end_line - $start_line;

$source = file($f);
$source = implode('', array_slice($source, 0, count($source)));
// $source = preg_split("/(\n|\r\n|\r)/", $source);
$source = preg_split("/".PHP_EOL."/", $source);

$body = '';
for($i=$start_line; $i<$end_line; $i++)
    $body.="{$source[$i]}\n";

echo $body;

감사합니다.최종기능

function get_function($method,$class=null){

    if (!empty($class)) $func = new ReflectionMethod($class, $method);
    else $func = new ReflectionFunction($method);

    $f = $func->getFileName();
    $start_line = $func->getStartLine() - 1;
    $end_line = $func->getEndLine();
    $length = $end_line - $start_line;

    $source = file($f);
    $source = implode('', array_slice($source, 0, count($source)));
    $source = preg_split("/".PHP_EOL."/", $source);

    $body = '';
    for($i=$start_line; $i<$end_line; $i++)
        $body.="{$source[$i]}\n";

    return $body;   
}

도 , 그 된 후\ReflectionFunction에는 시작 행과 끝 에 대한 정보만 포함되어 있으며, 같은 행에 여러 개가 존재하고 네스트될 수 있는 경우에는 폐쇄 코드를 추출하기 위해 코드를 작성할 필요가 있다고 생각하거나 짧은 폐쇄 코드를 작성할 필요가 있다고 생각됩니다(죄송한 것보다 안전합니다).첫 번째, 두 번째, 두 번째 등 어느 쪽인지 알아야 합니다.이는 인수 목록 또는 어레이로 전달된 경우 어느 정도 알 수 있습니다.

제 경우엔 아주 구체적인 욕구가 있지만, 폐쇄 코드를 얻는 일반적인 해결책이 다른 사람들에게 유용할 수도 있습니다. 그래서 여기서 그만 두겠습니다.

<?php
namespace Phluid\Transpiler;

use ReflectionFunction;

final class Source
{
    private const OPEN_NEST_CHARS = ['(', '[', '{'];
    private const CLOSE_NEST_CHARS = [')', ']', '}'];
    private const END_EXPRESSION_CHARS = [';', ','];

    public static function doesCharBeginNest($char)
    {
        return \in_array($char, self::OPEN_NEST_CHARS);
    }

    public static function doesCharEndExpression($char)
    {
        return \in_array($char, self::END_EXPRESSION_CHARS);
    }

    public static function doesCharEndNest($char)
    {
        return \in_array($char, self::CLOSE_NEST_CHARS);
    }

    public static function readFunctionTokens(ReflectionFunction $fn, int $index = 0): array
    {
        $file = \file($fn->getFileName());
        $tokens = \token_get_all(\implode('', $file));
        $functionTokens = [];
        $line = 0;

        $readFunctionExpression = function ($i, &$functionTokens) use ($tokens, &$readFunctionExpression) {
            $start = $i;
            $nest = 0;

            for (; $i < \count($tokens); ++$i) {
                $token = $tokens[$i];

                if (\is_string($token)) {
                    if (self::doesCharBeginNest($token)) {
                        ++$nest;
                    } elseif (self::doesCharEndNest($token)) {
                        if ($nest === 0) {
                            return $i + 1;
                        }

                        --$nest;
                    } elseif (self::doesCharEndExpression($token)) {
                        if ($nest === 0) {
                            return $i + 1;
                        }
                    }
                } elseif ($i !== $start && ($token[0] === \T_FN || $token[0] === \T_FUNCTION)) {
                    return $readFunctionExpression($i, $functionTokens);
                }

                $functionTokens[] = $token;
            }

            return $i;
        };

        for ($i = 0; $i < \count($tokens); ++$i) {
            $token = $tokens[$i];
            $line = $token[2] ?? $line;

            if ($line < $fn->getStartLine()) {
                continue;
            } elseif ($line > $fn->getEndLine()) {
                break;
            }

            if (\is_array($token)) {
                if ($token[0] === \T_FN || $token[0] === \T_FUNCTION) {
                    $functionTokens = [];
                    $i = $readFunctionExpression($i, $functionTokens);

                    if ($index === 0) {
                        break;
                    }

                    --$index;
                }
            }
        }

        return $functionTokens;
    }
}

Source::readFunctionTokens()메서드는 PHP의 출력과 유사한 출력을 반환합니다.\token_get_all()이 함수는 폐쇄 시작부터 끝까지 코드만 필터링합니다.따라서 PHP의 구문적 요구에 따라 문자열과 배열이 혼합되어 있습니다. 여기를 참조하십시오.

사용방법:

$fn = [fn() => fn() => $i = 0, function () { return 1; }];
$tokens = Source::readFunctionTokens(new \ReflectionFunction($fn[1]), 1);

두 번째 arg는 가장 바깥쪽 범위의 첫 번째 닫힘 코드를 반환하고, 1은 가장 바깥쪽 범위의 두 번째 닫힘 코드를 반환합니다.코드는 매우 거칠고 생소한 것이므로 사용하고 싶다면 정리하는 것이 좋습니다.모든 구문이 유효하고 기본적인 구문 규칙을 위반할 수 있기 때문에 매우 안정적이고 성능이 있을 것입니다.

이 피드에 다른 맛의 훌륭한 코드를 추가하겠습니다.이건 나한테 효과가 있었어.

self::classClassName::class대체하면 편집자가 파일을 쉽게 해결할 수 있습니다.

$methods = get_class_methods(self::class);

foreach ($methods as $method) {
    
    
    $func = new ReflectionMethod(self::class, $method);

    $f = $func->getFileName();

    $start_line = $func->getStartLine() - 1;

    $end_line = $func->getEndLine();

    $length = $end_line - $start_line;

    $source = file_get_contents($f);

    $source = preg_split('/' . PHP_EOL . '/', $source);

    $body = implode(PHP_EOL, array_slice($source, $start_line, $length));

    echo $body . PHP_EOL . PHP_EOL;
}

언급URL : https://stackoverflow.com/questions/7026690/reconstruct-get-source-code-of-a-php-function

반응형