2

I've been reading through the following somewhat similar questions:

But those are specific to class names only. I'm wondering if there is an efficient way (using token_get_all() or otherwise) to retrieve all the methods contained in all the classes within a specific folder?

My initial thoughts are that I could traverse the directory using the FilesystemIterator, then use the ReflectionClass to create instances of each one. Alternatively I could include each class if it hasn't been declared already, then use a combination of get_declared_classes and get_class_methods... But both of these seem like bad ideas as they would consume a lot of memory. Is there a more efficient way?

EDIT: My attempt using token_get_all()

function getDirectoryList($dir) {
    $dirList = $fileList = [];
    $iter = new FilesystemIterator($dir, FilesystemIterator::SKIP_DOTS);

    foreach ($iter as $file) {
        if ($file->isDir()) {
            $dirList[$file->getFilename()] = getDirectoryList($file->getPathname());
        } else {
            $fileList[$file->getFilename()] = $file->getFilename();
        }
    }

    uksort($dirList, 'strnatcmp');
    natsort($fileList);
    return $dirList + $fileList;
}

$path = '/var/www/html/dev/lib/framework/controllers';
$classes = getDirectoryList($path);
foreach ($classes as $class) {
    $file = $path . '/' . $class;
    echo $file . '<br />';
    $fp = fopen($file, 'r');
    $method = $namespace = $buffer = '';
    $i = 0;
    while (!feof($fp)) {
        $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_FUNCTION) {
                for ($j=$i+1;$j<count($tokens);$j++) {
                    if ($tokens[$j] === '{') {
                        $method = $tokens[$i+2][1];
                    }
                }
            }
        }
        echo '<pre>';
        var_dump($method);
        echo '</pre>';
    }
}

This gives me output as follows:

/var/www/html/dev/lib/framework/controllers/AuthController.php
string(8) "register"
string(14) "registerSubmit"
string(14) "registerSubmit"
string(14) "registerSubmit"
string(14) "registerSubmit"
string(14) "registerSubmit"
string(14) "registerSubmit"
string(14) "registerSubmit"
string(14) "registerSubmit"
string(5) "login"
string(5) "login"
string(5) "login"
string(5) "login"
string(5) "login"
string(5) "login"
string(6) "logout"
string(6) "verify"
string(6) "verify"
string(6) "verify"
string(6) "verify"
string(12) "verifySubmit"
string(12) "verifySubmit"
string(12) "verifySubmit"
string(12) "verifySubmit"
string(12) "verifySubmit"
string(12) "verifySubmit"
string(12) "verifySubmit"

Several of the methods are repeated. Also, it doesn't seem to catch all of the methods, for example loginSubmit should be listed. Here is a pastebin of the whole class as a reference. And I'm still not sure if this is even the most efficient way to do it?

Community
  • 1
  • 1
mister martin
  • 6,197
  • 4
  • 30
  • 63
  • So why not `token_get_all`? – zerkms Aug 02 '16 at 00:00
  • @zerkms I'm not sure how, considering there is no [parser token](http://php.net/manual/en/tokens.php) "method" equivalent of `T_CLASS` – mister martin Aug 02 '16 at 00:17
  • `T_FUNCTION` inside `T_CLASS` (only the first level of depth though) is a method. – zerkms Aug 02 '16 at 00:22
  • @zerkms I've tried with `T_FUNCTION` using the examples in the links provided to no avail. Even though they're only searching for a single class name, not multiple method names, I can't seem to get anything useful out of it. I can update my question with the failed attempts if you like. – mister martin Aug 02 '16 at 00:29
  • If you post your attempt - it increases chances to get an answer. See "help me with this code" vs "write everything for me" – zerkms Aug 02 '16 at 00:37
  • @zerkms updated with code example and (un)expected results. – mister martin Aug 02 '16 at 00:44
  • "for example loginSubmit should be listed" --- without having sources of the original file it's not obvious for us. – zerkms Aug 02 '16 at 00:56
  • @zerkms added pastebin. – mister martin Aug 02 '16 at 01:02
  • If you can figure out what the classes are (*if you have conventional naming*), why not use [`get_class_methods()`](http://php.net/manual/en/function.get-class-methods.php) on said class name in your loop to generate method names as required. (***Note:*** this fetches the defined methods within the class, not the ones called.) – Darren Aug 02 '16 at 01:14
  • @Darren because that would require every class to be declared first... As stated in the question. – mister martin Aug 02 '16 at 01:29
  • Whoops, read straight past that! – Darren Aug 02 '16 at 01:30
  • i tried this https://stackoverflow.com/a/4068490/1225672 and its working – aldo Oct 27 '19 at 06:03

0 Answers0