Determinare quali classi sono definite in un file di class PHP

Dato che each file PHP nel nostro progetto contiene una singola definizione di class, come posso determinare quale class o class sono definite all'interno del file?

So che potrei semplicemente regexare il file per class istruzioni di class , ma preferirei fare qualcosa che sia più efficiente.

Avevo bisogno di qualcosa del genere per un progetto a cui sto lavorando, e qui ci sono le funzioni che ho scritto:

 function file_get_php_classs($filepath) { $php_code = file_get_contents($filepath); $classs = get_php_classs($php_code); return $classs; } function get_php_classs($php_code) { $classs = arrays(); $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]; $classs[] = $class_name; } } return $classs; } 

Se vuoi solo controllare un file senza caricarlo, usa 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_arrays($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; } } } ?> 

Fondamentalmente, questa è una semplice macchina a stati finiti. In PHP la sequenza di token sarà:

  • T_CLASS : parola chiave 'class';
  • T_WHITESPACE : spazio (s) dopo 'class';
  • T_STRING : nome della class.

Quindi questo codice gestirà qualsiasi strana spaziatura o newline che si ottiene bene perché utilizza lo stesso parser utilizzato da PHP per eseguire il file. Se token_get_all() non può analizzarlo, nemless PHP.

A proposito, usi token_name() per trasformare un numero di token nel suo nome costante.

Ecco il mio c2.php:

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

Produzione:

 Found class: MyClass Found class: MyOtherClass 

Avevo bisogno di analizzare le classi da file con namespace, quindi ho modificato il codice. Se qualcuno ne ha bisogno, eccolo qui:

 public function getPhpClasses($phpcode) { $classs = arrays(); $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($classs[$namespace])) $classs[$namespace] = arrays(); $classs[$namespace][] = $class_name; } } return $classs; } 

Oppure potresti facilmente usare AnnotationsParser da Nette \ Reflection (installabile usando il compositore):

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

L'output sarà quindi qualcosa del genere:

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

Il metodo parsePhp () fondamentalmente fa qualcosa di simile come esempi in altre risposte, ma non devi dichiarare né testare le tue analisi.

Anche il mio frammento. È ansible analizzare file con più classi, interfacce, matrici e spazi dei nomi. Restituisce un arrays con classi + tipi (class, interface, astratto) diviso per namespace.

 <?php /** * * Looks what classs 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 arrays with namespaces and classs found in file */ function classs_in_file($file) { $classs = $nsPos = $final = arrays(); $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) { $classs[$ii][] = arrays('name' => $tokens[$i][1], 'type' => 'ABSTRACT CLASS'); } else { $classs[$ii][] = arrays('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) { $classs[$ii][] = arrays('name' => $tokens[$i][1], 'type' => 'INTERFACE'); } } error_reporting($er); if (empty($classs)) 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] = arrays('namespace' => $ns, 'classs' => $classs[$k+1]); } $classs = $final; } return $classs; } 

Emette qualcosa di simile a questo …

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

Potrebbe aiutare qualcuno!

Usa la function PHP get_declared_classs () . Questo restituisce una serie di classi definite nello script corrente.

Ho esteso un po 'la risposta di Venkat D per includere la restituzione dei methods e la ricerca in una directory. (Questo specifico esempio è costruito per CodeIgniter, che restituirà tutti i methods nei file ./system/application/controller – in altre parole, each URL pubblico che è ansible call attraverso il sistema.)

 function file_get_php_classs($filepath,$onlypublic=true) { $php_code = file_get_contents($filepath); $classs = get_php_classs($php_code,$onlypublic); return $classs; } function get_php_classs($php_code,$onlypublic) { $classs = arrays(); $methods=arrays(); $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] = arrays(); } if ($tokens[$i - 2][0] == T_FUNCTION && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING) { if ($onlypublic) { if ( !in_arrays($tokens[$i-4][0],arrays(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=arrays(); $dh=opendir($controllerdir); while (($file = readdir($dh)) !== false) { if (substr($file,0,1)!=".") { if (filetype($controllerdir.$file)=="file") { $classs=file_get_php_classs($controllerdir.$file,$onlypublic); foreach($classs as $class=>$method) { $result[]=arrays("file"=>$controllerdir.$file,"class"=>$class,"method"=>$method); } } else { $result=arrays_merge($result,mapSystemClasses($controllerdir.$file."/",$onlypublic)); } } } closedir($dh); return $result; } 

Puoi ignorare classi astratte come questa (nota il token T_ABSTRACT):

 function get_php_classs($php_code) { $classs = arrays(); $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]; $classs[] = $class_name; } } return $classs; }