문제

프로젝트의 각 PHP 파일에 단일 클래스 정의가 포함되어 있으면 파일 내에 어떤 클래스 또는 클래스가 정의되는지 결정할 수 있습니까?

파일을 다시 만날 수 있다는 것을 알고 있습니다 class 진술이지만 더 효율적인 일을하는 것을 선호합니다.

도움이 되었습니까?

해결책

내가 작업중 인 프로젝트를 위해 이와 같은 것이 필요했고 여기에 내가 쓴 기능이 있습니다.

function file_get_php_classes($filepath) {
  $php_code = file_get_contents($filepath);
  $classes = get_php_classes($php_code);
  return $classes;
}

function get_php_classes($php_code) {
  $classes = array();
  $tokens = token_get_all($php_code);
  $count = count($tokens);
  for ($i = 2; $i < $count; $i++) {
    if (   $tokens[$i - 2][0] == T_CLASS
        && $tokens[$i - 1][0] == T_WHITESPACE
        && $tokens[$i][0] == T_STRING) {

        $class_name = $tokens[$i][1];
        $classes[] = $class_name;
    }
  }
  return $classes;
}

다른 팁

로드하지 않고 파일을 확인하려면 사용합니다. token_get_all():

<?php
header('Content-Type: text/plain');
$php_file = file_get_contents('c2.php');
$tokens = token_get_all($php_file);
$class_token = false;
foreach ($tokens as $token) {
  if (is_array($token)) {
    if ($token[0] == T_CLASS) {
       $class_token = true;
    } else if ($class_token && $token[0] == T_STRING) {
       echo "Found class: $token[1]\n";
       $class_token = false;
    }
  }       
}
?>

기본적으로 이것은 간단한 유한 상태 기계입니다. php에서 토큰 될거야:

  • T_CLASS: '클래스'키워드;
  • T_WHITESPACE: '클래스'후 공간;
  • T_STRING: 클래스 이름.

따라서이 코드는 이상한 간격 또는 최신 라인을 처리하여 파일을 실행하기 위해 동일한 Parser PHP를 사용하기 때문에 괜찮습니다. 만약에 token_get_all() 그것을 구문 분석 할 수없고, PHP도 할 수 없습니다.

그건 그렇고, 당신은 사용합니다 token_name() 토큰 번호를 상수 이름으로 바꾸려면.

여기 내 C2.php입니다.

<?php
class MyClass {
  public __construct() {
  }
}

class MyOtherClass {
  public __construct() {
  }
}
?>

산출:

Found class: MyClass
Found class: MyOtherClass

네임 스페이스가있는 파일의 구문 분석이 필요하므로 코드를 수정했습니다. 누군가가 필요하다면 여기에 있습니다.

public function getPhpClasses($phpcode) {
    $classes = array();

    $namespace = 0;  
    $tokens = token_get_all($phpcode); 
    $count = count($tokens); 
    $dlm = false;
    for ($i = 2; $i < $count; $i++) { 
        if ((isset($tokens[$i - 2][1]) && ($tokens[$i - 2][1] == "phpnamespace" || $tokens[$i - 2][1] == "namespace")) || 
            ($dlm && $tokens[$i - 1][0] == T_NS_SEPARATOR && $tokens[$i][0] == T_STRING)) { 
            if (!$dlm) $namespace = 0; 
            if (isset($tokens[$i][1])) {
                $namespace = $namespace ? $namespace . "\\" . $tokens[$i][1] : $tokens[$i][1];
                $dlm = true; 
            }   
        }       
        elseif ($dlm && ($tokens[$i][0] != T_NS_SEPARATOR) && ($tokens[$i][0] != T_STRING)) {
            $dlm = false; 
        } 
        if (($tokens[$i - 2][0] == T_CLASS || (isset($tokens[$i - 2][1]) && $tokens[$i - 2][1] == "phpclass")) 
                && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING) {
            $class_name = $tokens[$i][1]; 
            if (!isset($classes[$namespace])) $classes[$namespace] = array();
            $classes[$namespace][] = $class_name;
        }
    } 
    return $classes;
}

또는 AnnotationsParser를 쉽게 사용할 수 있습니다 Nette 반사 (작곡가를 사용하여 설치 가능) :

use Nette\Reflection\AnnotationsParser;
$classes = AnnotationsParser::parsePhp(file_get_contents($fileName));
var_dump($classes);

출력은 다음과 같은 것입니다.

array(1) {
  ["Your\Class\Name"] =>
  array(...) {
      // property => comment
  },
  ["Your\Class\Second"] =>
  array(...) {
      // property => comment
  },
}

그만큼 parsephp () 메소드 기본적으로 다른 답변에서 예와 비슷한 일을하지만, 파싱을 스스로 선언하거나 테스트 할 필요는 없습니다.

내 스 니펫도. 여러 클래스, 인터페이스, 배열 및 네임 스페이스로 파일을 구문 분석 할 수 있습니다. 클래스+유형 (클래스, 인터페이스, 초록)을 네임 스페이스로 나눈 배열을 반환합니다.

<?php    
    /**
     * 
     * Looks what classes and namespaces are defined in that file and returns the first found
     * @param String $file Path to file
     * @return Returns NULL if none is found or an array with namespaces and classes found in file
     */
    function classes_in_file($file)
    {

        $classes = $nsPos = $final = array();
        $foundNS = FALSE;
        $ii = 0;

        if (!file_exists($file)) return NULL;

        $er = error_reporting();
        error_reporting(E_ALL ^ E_NOTICE);

        $php_code = file_get_contents($file);
        $tokens = token_get_all($php_code);
        $count = count($tokens);

        for ($i = 0; $i < $count; $i++) 
        {
            if(!$foundNS && $tokens[$i][0] == T_NAMESPACE)
            {
                $nsPos[$ii]['start'] = $i;
                $foundNS = TRUE;
            }
            elseif( $foundNS && ($tokens[$i] == ';' || $tokens[$i] == '{') )
            {
                $nsPos[$ii]['end']= $i;
                $ii++;
                $foundNS = FALSE;
            }
            elseif ($i-2 >= 0 && $tokens[$i - 2][0] == T_CLASS && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING) 
            {
                if($i-4 >=0 && $tokens[$i - 4][0] == T_ABSTRACT)
                {
                    $classes[$ii][] = array('name' => $tokens[$i][1], 'type' => 'ABSTRACT CLASS');
                }
                else
                {
                    $classes[$ii][] = array('name' => $tokens[$i][1], 'type' => 'CLASS');
                }
            }
            elseif ($i-2 >= 0 && $tokens[$i - 2][0] == T_INTERFACE && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING)
            {
                $classes[$ii][] = array('name' => $tokens[$i][1], 'type' => 'INTERFACE');
            }
        }
        error_reporting($er);
        if (empty($classes)) return NULL;

        if(!empty($nsPos))
        {
            foreach($nsPos as $k => $p)
            {
                $ns = '';
                for($i = $p['start'] + 1; $i < $p['end']; $i++)
                    $ns .= $tokens[$i][1];

                $ns = trim($ns);
                $final[$k] = array('namespace' => $ns, 'classes' => $classes[$k+1]);
            }
            $classes = $final;
        }
        return $classes;
    }

이와 같은 것을 출력합니다 ...

array
  'namespace' => string 'test\foo' (length=8)
  'classes' => 
    array
      0 => 
        array
          'name' => string 'bar' (length=3)
          'type' => string 'CLASS' (length=5)
      1 => 
        array
          'name' => string 'baz' (length=3)
          'type' => string 'INTERFACE' (length=9)
array
  'namespace' => string 'this\is\a\really\big\namespace\for\testing\dont\you\think' (length=57)
  'classes' => 
    array
      0 => 
        array
          'name' => string 'yes_it_is' (length=9)
          'type' => string 'CLASS' (length=5)
      1 => 
        array
          'name' => string 'damn_too_big' (length=12)
          'type' => string 'ABSTRACT CLASS' (length=14)
      2 => 
        array
          'name' => string 'fogo' (length=6)
          'type' => string 'INTERFACE' (length=9)

누군가를 도울 수 있습니다!

PHP의 기능을 사용하십시오 get_declared_classes (). 이것은 현재 스크립트에 정의 된 클래스 배열을 반환합니다.

나는 방법을 반환하고 디렉토리를 검색하도록 venkat d의 답변을 약간 확장했습니다. (이 특정 예제는 CodeIgniter를 위해 구축되며 ./system/application/controller 파일의 모든 메소드를 반환합니다. 즉, 시스템을 통해 호출 할 수있는 모든 공개 URL입니다.)

function file_get_php_classes($filepath,$onlypublic=true) {
    $php_code = file_get_contents($filepath);
    $classes = get_php_classes($php_code,$onlypublic);
    return $classes;
}

function get_php_classes($php_code,$onlypublic) {
    $classes = array();
    $methods=array();
    $tokens = token_get_all($php_code);
    $count = count($tokens);
    for ($i = 2; $i < $count; $i++) {
        if ($tokens[$i - 2][0] == T_CLASS
        && $tokens[$i - 1][0] == T_WHITESPACE
        && $tokens[$i][0] == T_STRING) {
            $class_name = $tokens[$i][1];
            $methods[$class_name] = array();
        }
        if ($tokens[$i - 2][0] == T_FUNCTION
        && $tokens[$i - 1][0] == T_WHITESPACE
        && $tokens[$i][0] == T_STRING) {
            if ($onlypublic) {
                if ( !in_array($tokens[$i-4][0],array(T_PROTECTED, T_PRIVATE))) {
                    $method_name = $tokens[$i][1];
                    $methods[$class_name][] = $method_name;
                }
            } else {
                $method_name = $tokens[$i][1];
                $methods[$class_name][] = $method_name;
            }
        }
    }
    return $methods;
}

function mapSystemClasses($controllerdir="./system/application/controllers/",$onlypublic=true) {
    $result=array();
    $dh=opendir($controllerdir);
    while (($file = readdir($dh)) !== false) {
        if (substr($file,0,1)!=".") {
            if (filetype($controllerdir.$file)=="file") {
                $classes=file_get_php_classes($controllerdir.$file,$onlypublic);
                foreach($classes as $class=>$method) {
                    $result[]=array("file"=>$controllerdir.$file,"class"=>$class,"method"=>$method);

                }
            } else {
                $result=array_merge($result,mapSystemClasses($controllerdir.$file."/",$onlypublic));
            }
        }
    }
    closedir($dh);
    return $result;
}

이와 같은 추상 클래스를 무시할 수 있습니다 (t_abstract 토큰 참고) :

function get_php_classes($php_code)
{
    $classes = array();
    $tokens = token_get_all($php_code);
    $count = count($tokens);
    for ($i = 2; $i < $count; $i++)
    {
        if ($tokens[$i - 2][0] == T_CLASS && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING && !($tokens[$i - 3] && $i - 4 >= 0 && $tokens[$i - 4][0] == T_ABSTRACT))
        {
            $class_name = $tokens[$i][1];
            $classes[] = $class_name;
        }
    }
    return $classes;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top