Php get all included classes

How do I find all the classes used in a PHP file?

I am trying to use the tokenizer to scan a file to find all the defined classes, anything they extend, any created instances, and anytime they were statically invoked.

 $token) < if(is_array($token)) < if(isset($tokens[$i - 2][0], $tokens[$i - 1][0])) < // new [class] if ($tokens[$i - 2][0] == T_NEW AND $tokens[$i - 1][0] == T_WHITESPACE) < if($tokens[$i][0] == T_STRING) < $used_classes[$token[1]] = TRUE; // new $variable() >elseif($tokens[$i][0] == T_VARIABLE) < // @todo, this is really broken. However, do best to look for the assignment if(preg_match('~\$var\s*=\s*([\'"])((?:(?!\1).)*)\1~', $text, $match)) < if(empty($extension_classes[$match[2]])) < $used_classes[$match[2]] = TRUE; >> elseif($token[1] !== '$this') < $variable_classes[$token[1]] = TRUE; >> > // class [class] if ($tokens[$i - 2][0] == T_CLASS AND $tokens[$i - 1][0] == T_WHITESPACE) < if($tokens[$i][0] == T_STRING) < $defined_classes[$token[1]] = TRUE; >> // @todo: find more classes \/ // class [classname] extends [class] . // [class]::method(). > > > 

There is magic constant __ FILE __ (with no spaces) in PHP. You can open (fopen or file_get_contents) this file and search it via preg_match (something like /^\sclass(.)$/ and /(.*)::(.*)/ and so). Know that quite not-straigh solution so maybe someone will found a better one. If you want to find all classes, you can use function get_declared_classes (php.net/manual/en/function.get-declared-classes.php) and so, but remember, that also core classes will be included.

Out of your three recommendations, only searching with regex has anything to do with static analysis of PHP code. However, I would rather avoid regex since the PHP parser is more trust-worthy. I also can’t imagine how complex the regex would have to be to find a variable variable.

Well, I’m afraid that full filling you request (finding class definition and calls in target file) is not possible.

4 Answers 4

Parsing and then interpreting PHP code is not something that can be solved well using a regex. You would need a something much more clever, like a state machine, that can actually understand things like scope, class names, inheritance etc to be able to do what you want.

It just so happens, that I happen to have written a PHP-to-Javascript converter based on a state-machine that will almost do most of what you want to do:

Yes, all the classes create a ClassScope with all their variables listed and their methods are created as FunctionScope’s, so you can tell which methods a class has.

Yes, every class has it’s parent classes listed in ClassScope->$parentClasses

Nope, but wouldn’t be hard to add extra code to record these.

anytime they were statically invoked.

Nope — but that actually could be done with a regex.

Although it doesn’t exactly solve your problem, the project as it stands would get you 95% of the way towards what you want to do, which would save a couple weeks work.

Inclued is probably worth looking into here, though I don’t think it will provide you with any data beyond which files/classes were included and how many times.

Читайте также:  Wordpress add html in header

That’s a good tool to know about, but unfortunately it requires that you run the code. I’m looking for static analysis since it’s not realistic to run every aspect of a PHP system which does not contain full code-coverage from unit tests.

I don’t think you can do this by just analyzing tokens.

You need to know, for any class name, what actual definition it represents, including any inheritance relations, and whether it has been used in your code to implement an interface. The class/interface definition may be in another file; that file may be included under some condition. You may have the same class name defined differently in different files. So in general you need to to process all the files that comprise your system at once.

What you need as a foundation is a tool that parses PHP and builds up real symbol tables. You might be able to compute your result from that. (Such a tool analyzes tokens as a starting place, but it is far more work than trivial token scanning).

It looks like if you just load the code, you can then use the built-in Reflection API (ReflectionClass::_construct(), etc.) to examine each class.

To get the classes themselves, use the built-in get_declared_classes().

(Note: I have not tried this, so YMMV.)

This isn’t really acceptable, however, perhaps I could fork a process and load the file (even if it trashes everything) and return the new functions/classes found.

This question is in a collective: a subcommunity defined by tags with relevant content and experts.

Источник

Get all defined classes of a parent class in php

Taking Wrikken’s answer and correcting it using Scott BonAmi’s suggestion and you get:

$children = array(); foreach( get_declared_classes() as $class )

The other suggestions of is_a() and instanceof don’t work for this because both of them expect an instance of an object, not a classname.

If you need that, it really smells like bad code, the base class shouldn’t need to know this.

However, if you definitions have been included (i.e. you don’t need to include new files with classes you possibly have), you could run:

$children = array(); foreach(get_declared_classes() as $class)

this is basically what I have, except I’m using is_a instead of instanceof . and I understand why you would think that, but the base class doesn’t actually need to know anything, this is more like a plugin manager function:)

Thanks @ScottBonAmi; your answer worked but is_a() and instanceof did not for me because both expect an object, not a classname.

Normally this should fail, because modern applications will use autoloading and in this case classes are not defined. get_declared_classes() will return a list of an undefined application state, because some classes are loaded and others not.

I’d like to add that, this does not smell like «Bad Code» — it’s more in the lines with Dynamic Class Reflection, which is why reflection functions exist and why there is a lot of benefit to dynamic class creation / loading.

Читайте также:  Python redis keys count

to get a list of all classes.

Then, use PHP’s Reflection feature to build the inheritance tree.

I know this is old now, but thank you for pointing me to the reflection classes, they lack the complete documentation of most of php.net, but they are extremely useful in a few different places +1

I am pretty sure that the following solution or some thing like that would be a good fit for your problem. IMHO, you can do the following (which is kind of observer pattern):

1- Define an interface call it Fooable

2- All your target classes must implement that interface:

class Fooer implements Fooable < public function doSomething()< return "doing something"; >> class SpecialFooer implements Fooable < public function doSomething()< return "doing something special"; >> 

3- Make a registrar class call it the FooRegisterar

class FooRegisterar < public static $listOfFooers =array(); public static function register($name, Fooable $fooer)< self::$listOfFooers[$name]=$fooer; >public static function getRegisterdFooers() < return self::$listOfFooers; >> 

4- Somewhere in your boot script or some script that is included in the boot script:

FooRegisterar::register("Fooer",new Fooer()); FooRegisterar::register("Special Fooer",new SpecialFooer()); 
class FooClient< public function fooSomething()< $fooers = FooRegisterar::getRegisterdFooers(); foreach($fooers as $fooer)< $fooer->doSomthing(); > > > 

let me ask you the question in a different way, why would you need this? I mean why would you need to get all the classes that do inherit a class without knowing them ahead of the time?

You marked your question as OOP that’s why I am posting this answer because this is how an OOP solution looks like 🙂

Doesn’t really matter why, when I asked this 5 years ago I was building a plugin auto loader, knowing that I could potentially have a few hundred plugins, but only a dozen on some page loads, the accepted answer allows me to cache the results and doesn’t require that I know about all of the classes or instantiate them.

Not sure how many different ways I can say this. The plugin system itself is OOP, I was looking for a dynamic way to find and register these plugins without instantiating them, your «solution» would be a possible way to implement the registration of plugins on page load, but doesn’t address the dynamic need of discovering the plugins. Where do you get «Fooer» and «Special Fooer» from if you don’t already know they exist?

no one is nervous, you didn’t answer my question, you provided a solution that would be perfectly acceptable if the requirements were different.

Источник

Get a list of all available classes with PHP

PHP has the function get_declared_classes() which allows you to get a list of all the available system and user defined classes in an array. This post looks at how to use the get_declared_classes() function, the output from it and how to sort the list into alphabetical order.

Using get_declared_classes()

get_declared_classes() returns a zero based array containing all the classes available to your script, including both system declared classes (such as PDO and XMLReader) and the classes you have declared yourself or from any 3rd party libraries you have included in your script.

Читайте также:  Upload php files to web server

The following example illustrates this (the examples below assume we have two user defined classed called foo and bar):

print_r(get_declared_classes());

and an extract of the result:

Array ( [0] => stdClass [1] => Exception [2] => ErrorException [3] => LibXMLError [4] => __PHP_Incomplete_Class [5] => php_user_filter . [100] => XMLWriter [101] => XSLTProcessor [102] => foo [103] => bar )

Sorting the result into alphabetical order

If you want to sort the list of classes into alphabetical order, you could do this instead:

$classes = get_declared_classes(); sort($classes); print_r($classes);

and an extract of the result:

Array ( [0] => AppendIterator [1] => ArrayIterator [2] => ArrayObject [3] => BadFunctionCallException [4] => BadMethodCallException [5] => CachingIterator . [100] => mysqli_stmt [101] => mysqli_warning [102] => php_user_filter [103] => stdClass )

Conclusion

The get_declaed_functions() function is a great way of getting a complete list of classes that are available on your install of PHP and from your own and 3rd party PHP libraries.

Источник

PHP: How to get all classes when using autoloader

I need to create instances of all classes that implement specific interface. It’s fairly easy when not using autoloader, however get_declared_classes() is not playing well with autoloaders. It will list a class only after it was instantiated with autoloader.

3 Answers 3

You can use dirty hack and require_once all classes before get_declared_classes() function call.

  1. At first do dump all classes to class map via composer dumpautoload —optimize
  2. Now you can fetch composer loader and require all files
 $res = get_declared_classes(); $autoloaderClassName = ''; foreach ( $res as $className) < if (strpos($className, 'ComposerAutoloaderInit') === 0) < $autoloaderClassName = $className; // ComposerAutoloaderInit323a579f2019d15e328dd7fec58d8284 for me break; >> $classLoader = $autoloaderClassName::getLoader(); foreach ($classLoader->getClassMap() as $path)

P.S. Don’t use it in production.

The first few lines can be skipped — requiring vendor/autoload.php returns the autoloader (eg, $classLoader = require(‘vendor/autoload.php’); )

I had similar use case for all *Sniff.php classes found in some directory.

And for your use case:

$src = __DIR__ . '/src'; $robotLoader = new Nette\Loaders\RobotLoader\RobotLoader; $robotLoader->setTempDirectory(__DIR__ . '/temp'); $robotLoader->addDirectory($src); $robotLoader->acceptFiles = ['*Suffix.php']; // optional to reduce file count $robotLoader->rebuild(); $foundClasses = array_keys($robotLoader->getIndexedClasses()); // filter in any way 

If you don’t keep track of which classes exist, autoloading won’t help you.

But the situation would be pretty much the same if you tried to include all files and see which classes would come out of it, when there would be a chance that you missed a file.

Whatever it is what you try to do: Try it differently. I highly doubt you have to instantiate ALL these classes when serving one single request. It would not be very beneficial to the performance if you had to scan ALL declared classes for an interface, and then create an instance for all of them.

Provide some kind of registering method to let the application know about your classes. If you really have to use them all, so be it. But scanning whatever code has been run previously does not sound right (and you didn’t explain what you do at all).

Источник

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