views:

290

answers:

4

I want to create a function which receives a single argument that holds the path to a PHP file and then parses the given file and returns something like this:

class NameOfTheClass
   function Method1($arg1, $arg2, $arg2)
   private function Method2($arg1, $arg2, $arg2)
   public function Method2($arg1, $arg2, $arg2)

abstract class AnotherClass
   function Method1($arg1, $arg2, $arg2)
   private function Method2($arg1, $arg2, $arg2)
   public function Method2($arg1, $arg2, $arg2)

function SomeFunction($arg1, $arg2, $arg3)

This function should return all the classes, methods and function that exist in the given file with all the defined identifiers (abstract, public, private, protected, static, extends, interfaces, ...).

My first tought was to use regular expressions to do this, however these behave quite badly with comments, ie: /* this function returns(max(salary)) */ and become quite complex if I want to properly support scopes.

Another possible solution was to use the following built-in PHP functions:

get_declared_classes
get_declared_interfaces
get_defined_functions
get_class_methods

However these functions don't allow me to see the file where the classes / methods / functions are defined and thus it's not very useful.

I believe the Tokenizer extension is the solution for my problem, however I have never used this extension before and was hoping someone could give some advice and help me out with a basic implementation example.

+1  A: 

Hi,

Like you found out yourself, regex are quite not the right tool for the job, here ^^

And, like you said, the built-in functions you proposed are not that helpful either -- only thing that might be helpful is that they allow you to know which class exists... But they'll return builtin classes too :-(

Using the Tokenizer extension seems a bit overkill/hard to me ; I would probably not go that way, actually : too "low-level", I suppose.


Instead, I would take a look at PHP's Reflection API : it exists exactly to reverse-engineer classes, interfaces, functions, ...

So, I suppose it would be quite well-suited for what you are trying to do.


Edit : here is a quick example :

First, let's try to do reflection on a class :

include dirname(__FILE__) . '/temp-2.php';
$rC = new ReflectionClass('MyFirstClass');

You can now find out in which file it was declared, and which methods are in it :

var_dump($rC->getFileName());
var_dump($rC->getMethods());

Which will get you :

string '/home/squale/developpement/tests/temp/temp-2.php' (length=48)

array
  0 => &
    object(ReflectionMethod)[2]
      public 'name' => string '__construct' (length=11)
      public 'class' => string 'MyFirstClass' (length=12)
  1 => &
    object(ReflectionMethod)[3]
      public 'name' => string 'glop' (length=4)
      public 'class' => string 'MyFirstClass' (length=12)


And now, to get informations on each method :

foreach ($rC->getMethods() as $rM) {
    var_dump($rM, $rM->getParameters());
    echo '-----';
}

You'll get :

object(ReflectionMethod)[3]
  public 'name' => string '__construct' (length=11)
  public 'class' => string 'MyFirstClass' (length=12)

array
  0 => &
    object(ReflectionParameter)[4]
      public 'name' => string 'arg1' (length=4)
  1 => &
    object(ReflectionParameter)[5]
      public 'name' => string 'arg2' (length=4)

-----

object(ReflectionMethod)[2]
  public 'name' => string 'glop' (length=4)
  public 'class' => string 'MyFirstClass' (length=12)

array
  0 => &
    object(ReflectionParameter)[5]
      public 'name' => string 'a' (length=1)


From there, you should be able to dig a bit more ; and arrive to what you first asked ;-)


As a sidenote : there is one thing I have no idea about is : "how to find which classes / methods are declared in a given file" :-(

If anyone has an idea, it'll be welcome !

Pascal MARTIN
Thanks, seems the Reflection API is a strong candidate to solve my problem. Do you know where I can see an example of a similar implementation to my problem? Also, does the Reflection API allows me to distinguish in which files are the found methods / classes?
Alix Axel
Hi! I've edited my answer to provide some example :-) Hope this helps!
Pascal MARTIN
A: 

I can't help you with your particular question, as I've never used Tokenizer either.

You don't mention what you're using this for, but would something like phpDoc do what you need?

mabwi
What I need is basically a stripped down version of phpDoc without the hassle of phpDoc, basically I just want to get a glimpse of all the available methods and arguments of any given file - that would be more than enough for me.
Alix Axel
+6  A: 

If you are using PHP 5, the Reflection API is your tool.

Example:

$class = new ReflectionClass("NameOfTheClass");
$methods = $class->getMethods();
foreach($methods as $m) {
    print $m->name;
    $m->isPrivate() ? print "Private" : print "";
    $m->isPublic() ? print "Public" : print "";
    $params = $m->getParameters();
    foreach($params as $p) {
        print $p->getName();
        }
}
Davide Gualano
This pretty much covers all my needs, one more question tough: what about functions (not methods)?
Alix Axel
You can use get_defined_functions() to get all the functions defined by you, anche than the ReflectionFunction class (http://www.php.net/manual/en/class.reflectionfunction.php) to analyze them.
Davide Gualano
A: 

I suggest the following procedure:

  1. store the current output of get_declared_classes, get_declared_interfaces and get_defined_functions(if you really need to support them)
  2. include the file
  3. compare get_declared_classes, get_declared_interfaces and get_defined_functions with the ones you stored to see what's new
  4. use reflection to analyze them
  5. goto step 2 for the next file
André Hoffmann