Php name class files

Get class name from file

I have a php file which contains only one class. how can I know what class is there by knowing the filename? I know I can do something with regexp matching but is there a standard php way? (the file is already included in the page that is trying to figure out the class name).

11 Answers 11

There are multiple possible solutions to this problem, each with their advantages and disadvantages. Here they are, it’s up to know to decide which one you want.

Tokenizer

This method uses the tokenizer and reads parts of the file until it finds a class definition.

  • Do not have to parse the file entirely
  • Fast (reads the beginning of the file only)
  • Little to no chance of false positives

Disadvantages

$fp = fopen($file, 'r'); $class = $buffer = ''; $i = 0; while (!$class) < if (feof($fp)) break; $buffer .= fread($fp, 512); $tokens = token_get_all($buffer); if (strpos($buffer, '<') === false) continue; for (;$i> > > > 

Regular expressions

Use regular expressions to parse the beginning of the file, until a class definition is found.

Disadvantages

$fp = fopen($file, 'r'); $class = $buffer = ''; $i = 0; while (!$class) < if (feof($fp)) break; $buffer .= fread($fp, 512); if (preg_match('/class\s+(\w+)(.*)?\> 

Note: The regex can probably be improved, but no regex alone can do this perfectly.

Get list of declared classes

This method uses get_declared_classes() and look for the first class defined after an include.

Читайте также:  Python обучение нейросети tensorflow

Disadvantages

  • Have to load the entire file
  • Have to load the entire list of classes in memory twice
  • Have to load the class definition in memory
$classes = get_declared_classes(); include 'test2.php'; $diff = array_diff(get_declared_classes(), $classes); $class = reset($diff); 

Note: You cannot simply do end() as others suggested. If the class includes another class, you will get a wrong result.

This is the Tokenizer solution, modified to include a $namespace variable containing the class namespace, if applicable:

$fp = fopen($file, 'r'); $class = $namespace = $buffer = ''; $i = 0; while (!$class) < if (feof($fp)) break; $buffer .= fread($fp, 512); $tokens = token_get_all($buffer); if (strpos($buffer, '<') === false) continue; for (;$ielse if ($tokens[$j] === ' > > if ($tokens[$i][0] === T_CLASS) < for ($j=$i+1;$j> > > > 

. or the alternative syntax:

namespace foo\bar; class hello

You should have the following result:

var_dump($namespace); // \foo\bar var_dump($class); // hello 

You could also use the above to detect the namespace a file declares, regardless of it containing a class or not.

How would this work to include namespaces of the class as well? As in, returning the FULL class name prefixed with namespaces?

There is a problem when using Tokenizer solution and fread($fp, 512) returns code with «unfinished» comment, passing this string to token_get_all will result in PHP Warning «Unterminated comment starting line x. » this renders Tokenizer solution useless if you’re using comments in code.

@netcoder For PHP 5.5+ code tokenizer solution gives false positive on use ::class statement because it have T_CLASS token code. Example: print_r(token_get_all(‘

You can make PHP do the work by just including the file and get the last declared class:

$file = 'class.php'; # contains class Foo include($file); $classes = get_declared_classes(); $class = end($classes); echo $class; # Foo 

If you need to isolate that, wrap it into a commandline script and execute it via shell_exec :

$file = 'class.php'; # contains class Foo $class = shell_exec("php -r \"include('$file'); echo end(get_declared_classes());\""); echo $class; # Foo 

If you dislike commandline scripts, you can do it like in this question, however that code does not reflect namespaces.

I can’t, the file is included automatically before my file runs and its not the last that is included.

@Dani: I added an example how to do that via commandline, however, you might run into problems when a class depends on another one etc. — however it should show you the idea.

Note that this approach require working autoloader for all parent classes and implemented interfaces. It also executes PHP code outside the class declaration (if such code exists), which may be undesired.

I modified Nette\Reflection\AnnotationsParser that so it returns an array of namespace+classname that are defined in the file

$parser = new PhpParser(); $parser->extractPhpClasses('src/Path/To/File.php'); class PhpParser < public function extractPhpClasses(string $path) < $code = file_get_contents($path); $tokens = @token_get_all($code); $namespace = $class = $classLevel = $level = NULL; $classes = []; while (list(, $token) = each($tokens)) < switch (is_array($token) ? $token[0] : $token) < case T_NAMESPACE: $namespace = ltrim($this->fetch($tokens, [T_STRING, T_NS_SEPARATOR]) . '\\', '\\'); break; case T_CLASS: case T_INTERFACE: if ($name = $this->fetch($tokens, T_STRING)) < $classes[] = $namespace . $name; >break; > > return $classes; > private function fetch(&$tokens, $take) < $res = NULL; while ($token = current($tokens)) < list($token, $s) = is_array($token) ? $token : [$token, $token]; if (in_array($token, (array) $take, TRUE)) < $res .= $s; >elseif (!in_array($token, [T_DOC_COMMENT, T_WHITESPACE, T_COMMENT], TRUE)) < break; >next($tokens); > return $res; > > 
$st = get_declared_classes(); include "classes.php"; //one or more classes in file, contains class class1, class2, etc. $res = array_values(array_diff_key(get_declared_classes(),$st)); print_r($res); # Array ([0] => class1 [1] => class2 [2] . ) 

Thanks to some people from Stackoverflow and Github, I was able to write this amazing fully working solution:

/** * get the full name (name \ namespace) of a class from its file path * result example: (string) "I\Am\The\Namespace\Of\This\Class" * * @param $filePathName * * @return string */ public function getClassFullNameFromFile($filePathName) < return $this->getClassNamespaceFromFile($filePathName) . '\\' . $this->getClassNameFromFile($filePathName); > /** * build and return an object of a class from its file path * * @param $filePathName * * @return mixed */ public function getClassObjectFromFile($filePathName) < $classString = $this->getClassFullNameFromFile($filePathName); $object = new $classString; return $object; > /** * get the class namespace form file path using token * * @param $filePathName * * @return null|string */ protected function getClassNamespaceFromFile($filePathName) < $src = file_get_contents($filePathName); $tokens = token_get_all($src); $count = count($tokens); $i = 0; $namespace = ''; $namespace_ok = false; while ($i < $count) < $token = $tokens[$i]; if (is_array($token) && $token[0] === T_NAMESPACE) < // Found namespace declaration while (++$i < $count) < if ($tokens[$i] === ';') < $namespace_ok = true; $namespace = trim($namespace); break; >$namespace .= is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i]; > break; > $i++; > if (!$namespace_ok) < return null; >else < return $namespace; >> /** * get the class name form file path using token * * @param $filePathName * * @return mixed */ protected function getClassNameFromFile($filePathName) < $php_code = file_get_contents($filePathName); $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[0]; > 

Источник

tbreuss / get_class_name.php

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

/**
* Get class name from file
*
* This is a working example, that works for PHP 7.4 and 8.x.
*
* @see https://stackoverflow.com/questions/7153000/get-class-name-from-file
*/
function get_class_name ( string $ file ): string
$ tokens = token_get_all(file_get_contents( $ file ));
$ tokensCount = count( $ tokens );
$ className = » ;
$ namespaceName = » ;
for ( $ i = 0 ; $ i < $ tokensCount ; $ i ++)
// namespace token
if (is_array( $ tokens [ $ i ]) && (token_name( $ tokens [ $ i ][ 0 ]) === ‘T_NAMESPACE’ ))
for ( $ j = $ i + 1 ; $ j < $ tokensCount ; $ j ++)
if ( $ tokens [ $ j ][ 0 ] === ‘;’ )
break ;
>
$ tokenName = token_name( $ tokens [ $ j ][ 0 ]);
if ( $ tokenName === ‘T_WHITESPACE’ )
continue ;
>
if (in_array( $ tokenName , [ ‘T_NAME_QUALIFIED’ , ‘T_NS_SEPARATOR’ , ‘T_STRING’ ]))
$ namespaceName .= $ tokens [ $ j ][ 1 ];
>
>
>
// class token
if (is_array( $ tokens [ $ i ]) && (token_name( $ tokens [ $ i ][ 0 ]) === ‘T_CLASS’ ))
for ( $ j = $ i + 1 ; $ j < count( $ tokens ); $ j ++)
$ tokenName = token_name( $ tokens [ $ j ][ 0 ]);
if ( $ tokenName === ‘T_WHITESPACE’ )
continue ;
>
if ( $ tokenName === ‘T_STRING’ )
$ className = $ tokens [ $ j ][ 1 ];
break ;
>
>
>
>
if (strlen( $ namespaceName ) === 0 )
return $ className ;
>
return $ namespaceName . ‘\\’ . $ className ;
>

Источник

Identifying class names from $_SERVER[‘SCRIPT_FILENAME’]

What is the best way to obtain the class name for a requested PHP file if my unknown class follows the following pattern?

index.php

startup.php

getView(); //Todo: Find the class from $_SERVER['SCRIPT_FILENAME'] //Todo: Once we find the class create an instance and call getView() exit; ?> 

view.php

I’m thinking a regular expression solution might be simple since the desired data will always be between ‘class’ and ‘extends’. I don’t have much experience formulating the desired expression and would appreciate some insight. The following solution may or may not be a good way of doing this, but it did lead me to a non-regular expression solution which is always a plus. If anyone can improve on this, then I will gladly give them credit for both my questions above. Credit actually goes to @Nik answering Stack Overflow question Extracting function names from a file (with or without regular expressions). If I do this in my startup script then I can probably count on the unknown class being the last one in the array. However, I plan on integrating this into my framework and would like a more complete solution. Since the class name is unknown, you may ask how can we be sure? Well, the abstract class View comes right before the unknown class in the array. Any solution would surely have to check for this. So without guarantee the last class is the needed class, I probably need to traverse backwards in the array until I have identified the abstract View class and the previous value in the array would be the unknown subclass.

startup.php

getView(); //Todo: Find the class from $_SERVER['SCRIPT_FILENAME'] //Todo: Once we find the class create an instance and call getView() $Classes = get_declared_classes(); $ViewObject = array_pop($Classes); $NewPage = new $ViewObject(); $NewPage->getView(); exit; ?> 

Please expand any opinions on this usage. So this solution only works if I include my abstract View class immediately before I include the unknown subclass script again via include($_SERVER[‘SCRIPT_FILENAME’]); . So this implies the get_declared_classes() function adds the classes in the order they were defined or included. This could be a problem.

getView(); //Todo: Find the class from $_SERVER['SCRIPT_FILENAME'] //Todo: Once we find the class create an instance and call getView() $Classes = get_declared_classes(); $ViewObject = array_pop($Classes); $NewPage = new $ViewObject(); $NewPage->getView(); exit; ?> 

Источник

Оцените статью