- check if class exists within file without requiring/including
- 4 Answers 4
- Saved searches
- Use saved searches to filter your results more quickly
- License
- violet-php/class-scanner
- Name already in use
- Sign In Required
- Launching GitHub Desktop
- Launching GitHub Desktop
- Launching Xcode
- Launching Visual Studio Code
- Latest commit
- Git stats
- Files
- README.md
- About
- наличие класса в файле php
- 3 ответа 3
check if class exists within file without requiring/including
Is there a way to check if class exists within a file without including/requiring the class? Something like: class_in_file($file); As I already mentioned, I know this can be done with requiring/including the class and then looking up class_exists($class); , but any other ways?
Well no. as it stills requires the file to check if the class exists in that file. otherwise how else would it know? if you had a class_in_file it would still need to read the file.
I need this for dynamic navigation built from PHP files. And only if the file contains specific class.
And my question is, again, why one would need that. Do you have a menu directory, from where you’ll read all PHP files and include them if they contain class MenuItem or something like that? And there isn’t another solution? But I see you’ve accepted an answer, so good luck. 🙂
4 Answers 4
$tokens = token_get_all(file_get_contents('foo.php'));
Then go through the tokens to see if you can spot a certain T_CLASS entry.
performance wise, what would be the difference with including/requiring the file? I think both methods have to load the entire file.
@Dann Performance wise including the file would be a lot faster. But the OP apparently doesn’t want to do that.
A php file is a text file, you can open it and parse it in order to find a class declaration.
It isn’t a simple process, but a good parser should make the task trivial.
You have to strike out commented lines, strings containing a class declaration can trigger a false-positive, heredocs tend to make things more complex. Evals should be taken in account also.
if you have access to a command line php interpreter, then you can have a look at -w switch that strips comments and whitespaces for you doing a good half of yor work for you.
The short answer is no. There are only workarounds. For example, you could parse the file yourself (perhaps using token_get_all ), or perhaps mark the file somehow with a comment at the top like
and read the first few lines looking for this with a preg_match .
PHP will only know which classes exist if it has loaded (parsed) the files they’re defined in (assuming they’re not built in). If you have a clearly defined structure (maybe you’re using autoloading), you could possibly check that a class exists simply by checking that the file that defines it exists. e.g. if (file_exists(‘/lib/Myapp/Util/Http.php’)) could be used as a check that the Myapp_Util_Http class exists in your app directories. It’s no guarantee the class does actually exist in that file though. For that you either have to include/require it, read it and parse it, or use autoloading and try using it.
This question is in a collective: a subcommunity defined by tags with relevant content and experts.
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
PHP Library for finding classes in PHP files by parsing them
License
violet-php/class-scanner
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
The Class Scanner library provides a convenient interface for finding classes defined in PHP source code. The purpose of this library is to be able to find classes within a class hierarchy without the need of actually executing the code and loading the classes into memory.
Normally if you want to find, for example, all child classes for a specific class in PHP, you would probably first need to include all the files that contain all the possible classes and then construct a hierarchy using class reflection by inspect all defined classes. Sometimes, however, including every file may not be possible, or may even be dangerous.
This library offers an alternative by allowing you to scan files for class definitions without the need of executing them in order to find classes based on their hierarchy or just for determining what classes are defined in which files.
Installation of this library is supported via composer. To install this library in your project, follow these steps:
- Install composer by following composer download instructions
- Add this library to your project by running composer require violet/class-scanner
The basic question this library intends to help answer, is which classes in your codebase extend a specific class.
Let’s say, for example, you want to find all classes in your project that extend that class Application\Controller . In order to do this, you could do:
require 'vendor/autoload.php'; $scanner = new Violet\ClassScanner\Scanner(); $scanner->scanDirectory('src'); foreach ($scanner->getSubClasses(Application\Controller::class) as $name) < echo $name; >
The scanner class provides the basic functionality of the library. For scanning class definitions from source code, it provides the following methods:
- scanFile(string $filename) — Scans this given filename for definitions
- scanDirectory(string $directory) — Scans all the files in the directory for definitions, but does not travers directories recursively
- scan(iterable $files) — Takes an iterable of file paths or instances of SplFileObject to scan.
- parse(string $code) — Parses the given string as PHP code to scan for class definitions.
All the scan* functions returns the scanner itself, so you can use it like a fluent interface, e.g.
require 'vendor/autoload.php'; $classes = (new Violet\ClassScanner\Scanner()) ->scanDirectory('controllers') ->scanDirectory('reporting') ->getClasses();
The parse() function, however, returns list of all the TypeDefinition instances from the parsed code.
To get the scanned classes, the scanner has two methods:
- getClasses(int $filter = TypeDefinition::TYPE_ANY) — Returns the names of all classes from the parsed files. The filter indicates the types of definitions to return.
- getSubClasses(string $class, int $filter = TypeDefinition::TYPE_CLASS) — Returns the names of all the child classes (inspected recursively) for the given class name. The second parameter allows to filter the types of returned names.
By default, the getClasses() returns all type definitions from the files. This includes classes, abstract classes, interfaces and traits. Both getClasses() and getSubClasses() have a filter parameter to return only specific kinds of types. The allowed types are:
- Violet\Scanner\TypeDefinition::TYPE_CLASS — Filters only instantiable classes and does not include abstract classes
- Violet\Scanner\TypeDefinition::TYPE_ABSTRACT — Filters for abstract class definitions
- Violet\Scanner\TypeDefinition::TYPE_INTERFACE — Filters for interfaces
- Violet\Scanner\TypeDefinition::TYPE_TRAIT — Filters for traits
- Violet\Scanner\TypeDefinition::TYPE_ANY — Filters for any type
The types can be combined with binary or operator, e.g. TypeDefinition::TYPE_CLASS | TypeDefinition::TYPE_ABSTRACT
If you need to implement more complex logic, you may want to use the TypeDefintion objects created from the parsed code. You can use the method getDefinitions(array $classes) to get definitions for the listed classes.
To get all definition from the scanned files you can use, for example:
$definitions = $scanner->getDefinitions($scanner->getClasses());
Note that even if you provide only one name, the array may contain multiple type definitions if the same type is defined multiple times in the scanned files.
Scanning all sub directories and excluding specific paths
About
PHP Library for finding classes in PHP files by parsing them
наличие класса в файле php
В этом же цикле хочу проверять в каждом файле существует ли класс (любой, не какой-то определенный) и выводить его название, если он существует.
Можно, конечно, сначала проверить существование класса class_exists() убедиться, что его нет, потом include файл и снова проверить class_exists() — но, наверное, это немного не то.
3 ответа 3
Самый надежный вариант — использовать token_get_all
$tokens = token_get_all(file_get_contents(file)); $classStart = false; foreach ($tokens as $token) < if ($token[0] === T_CLASS) < $classStart = true; >if ($classStart && $token[0] === T_STRING) < $class = $token[1]; break; >>
Более развернутый пример поиска класса(с пространством имен) в файле можете посмотреть у меня в проекте на гитхабе
@Aid Как раз для подобных случаев — язык то динамически компилируемый, работающий на сырых исходниках, сталобыть почему бы и нет?
Это да, однако «почему бы нет» — весьма недальновидное решение для подобных продуктов. Это же не домашний проектик, тут каждый шаг должен иметь сакральный или, хотя бы, финансовый смысл. Хотя в пыхе таких странностей навалом.
@Aid Если вспомнить историю PHP, то начинался он именно что как домашний проектик и до сих пор в большОй своей части развивается таки сообществом
Можно парсить каждый файл и проверять следующим образом, есть ли в нем классы. Наверно это костыль, но рабочий:
я сдела таким образом, он отрабаывает прекрастно:
$dir = WWW.'/libs'; $arrayLibs = array(); if($handle = opendir($dir))< while(false !== ($file = readdir($handle))) < if($file != "." && $file != "..")< $className = substr($file, 0, -4); require_once $dir.'/'.$file; if (class_exists($className)) $arrayLibs[] = 'Class name: '.$className; else $arrayLibs[] = 'Class '.$className.' dont exist'; > > > print_r($arrayLibs);
1) Работает только если имя файла соответствует классу, что далеко не всегда так. 2) Если в двух файлах будут классы с одним и тем-же именем, то будет печалька 3) Данное решение дает побочные эффекты, а именно загрузку всех классов в контекст исполнения скрипта, что не факт, что нужно
по идее они будут записываться только в определенный массив и вызываться по необходимости, и имя файлов обязательно должны совпадать с именами классов. поэтому совпадений быть почти не должно