Определение классов, определенных в файле класса PHP

Учитывая, что каждый 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 : ключевое слово 'class';
  • T_WHITESPACE : пробел (ы) после 'класса';
  • T_STRING : имя класса.

Таким образом, этот код будет обрабатывать любые странные интервалы или новые строки, которые вы получите просто отлично, потому что он использует тот же парсер, который использует 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 \ Reflection (устанавливаемый с помощью композитора):

 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 'fodass' (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; }