Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
352 views
in Technique[技术] by (71.8m points)

php - 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).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

Advantages

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

Disadvantages

  • Longest solution

Code

$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<count($tokens);$i++) {
        if ($tokens[$i][0] === T_CLASS) {
            for ($j=$i+1;$j<count($tokens);$j++) {
                if ($tokens[$j] === '{') {
                    $class = $tokens[$i+2][1];
                }
            }
        }
    }
}

Regular expressions

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

Advantages

  • Do not have to parse the file entirely
  • Fast (reads the beginning of the file only)

Disadvantages

  • High chances of false positives (e.g.: echo "class Foo {";)

Code

$fp = fopen($file, 'r');
$class = $buffer = '';
$i = 0;
while (!$class) {
    if (feof($fp)) break;

    $buffer .= fread($fp, 512);
    if (preg_match('/classs+(w+)(.*)?{/', $buffer, $matches)) {
        $class = $matches[1];
        break;
    }
}

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.

Advantages

  • Shortest solution
  • No chance of false positive

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

Code

$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 (;$i<count($tokens);$i++) {
        if ($tokens[$i][0] === T_NAMESPACE) {
            for ($j=$i+1;$j<count($tokens); $j++) {
                if ($tokens[$j][0] === T_STRING) {
                     $namespace .= '\'.$tokens[$j][1];
                } else if ($tokens[$j] === '{' || $tokens[$j] === ';') {
                     break;
                }
            }
        }

        if ($tokens[$i][0] === T_CLASS) {
            for ($j=$i+1;$j<count($tokens);$j++) {
                if ($tokens[$j] === '{') {
                    $class = $tokens[$i+2][1];
                }
            }
        }
    }
}

Say you have this class:

namespace fooar {
    class hello { }
}

...or the alternative syntax:

namespace fooar;
class hello { }

You should have the following result:

var_dump($namespace); // fooar
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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...