Php find classes in folder

PHP – получить все имена классов внутри определенного пространства имен

Я хочу получить все классы внутри пространства имен. У меня есть что-то вроде этого:

#File: MyClass1.php namespace MyNamespace; class MyClass1() < . >#File: MyClass2.php namespace MyNamespace; class MyClass2() < . >#Any number of files and classes with MyNamespace may be specified. #File: ClassHandler.php namespace SomethingElse; use MyNamespace as Classes; class ClassHandler < public function getAllClasses() < // Here I want every classes declared inside MyNamespace. >> 

Я попытался get_declared_classes() внутри getAllClasses() но MyClass1 и MyClass2 не были в списке.

Общий подход состоял бы в том, чтобы получить в своем проекте все полностью квалифицированные классы (класс с полным пространством имен), а затем отфильтровать требуемое пространство имен.

PHP предлагает некоторые собственные функции для получения этих классов (get_declared_classes и т. Д.), Но они не смогут найти классы, которые не были загружены (include / require), поэтому он не будет работать так, как ожидалось, с автозагрузчиками (например, Composer for пример). Это серьезная проблема, поскольку использование автозагрузчиков очень распространено.

Поэтому ваш последний способ – найти все файлы PHP самостоятельно и проанализировать их, чтобы извлечь их пространство имен и класс:

$path = __DIR__; $fqcns = array(); $allFiles = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); $phpFiles = new RegexIterator($allFiles, '/\.php$/'); foreach ($phpFiles as $phpFile) < $content = file_get_contents($phpFile->getRealPath()); $tokens = token_get_all($content); $namespace = ''; for ($index = 0; isset($tokens[$index]); $index++) < if (!isset($tokens[$index][0])) < continue; >if (T_NAMESPACE === $tokens[$index][0]) < $index += 2; // Skip namespace keyword and whitespace while (isset($tokens[$index]) && is_array($tokens[$index])) < $namespace .= $tokens[$index++][1]; >> if (T_CLASS === $tokens[$index][0]) < $index += 2; // Skip class keyword and whitespace $fqcns[] = $namespace.'\\'.$tokens[$index][1]; >> > 

Если вы следуете стандартам PSR 0 или PSR 4 (ваше дерево каталогов отражает ваше пространство имен), вам не нужно ничего фильтровать: просто укажите путь, который соответствует требуемому пространству имен.

Если вы не являетесь поклонником копирования / вставки приведенных выше фрагментов кода, вы можете просто установить эту библиотеку: https://github.com/gnugat/nomo-spaco . Если вы используете PHP> = 5.5, вы также можете использовать следующую библиотеку: https://github.com/hanneskod/classtools .

Я не был доволен ни одним из решений здесь, поэтому я закончил создание своего класса, чтобы справиться с этим. Это решение требует, чтобы вы :

Вкратце, этот класс пытается выяснить, где классы фактически живут в вашей файловой системе на основе пространств имен, которые вы определили в composer.json . Например, классы, определенные в пространстве имен Backup\Test находятся в /home/hpierce/BackupApplicationRoot/src/Test . Этому можно доверять, так как сопоставление структуры каталогов в пространстве имен требуется PSR-4 :

Сопряженные имена подпоследовательности после «префикса пространства имен» соответствуют подкаталогу в «базовом каталоге», в котором разделители пространства имен представляют разделители каталогов. Имя подкаталога ДОЛЖНО соответствовать случаю имен под-имен.

Возможно, вам придется настроить appRoot чтобы указать на каталог, содержащий composer.json .

, $files); return array_filter($classes, function($possibleClass)< return class_exists($possibleClass); >); > private static function getDefinedNamespaces() < $composerJsonPath = self::appRoot . 'composer.json'; $composerConfig = json_decode(file_get_contents($composerJsonPath)); //Apparently PHP doesn't like hyphens, so we use variable variables instead. $psr4 = "psr-4"; return (array) $composerConfig->autoload->$psr4; > private static function getNamespaceDirectory($namespace) < $composerNamespaces = self::getDefinedNamespaces(); $namespaceFragments = explode('\\', $namespace); $undefinedNamespaceFragments = []; while($namespaceFragments) < $possibleNamespace = implode('\\', $namespaceFragments) . '\\'; if(array_key_exists($possibleNamespace, $composerNamespaces))< return realpath(self::appRoot . $composerNamespaces[$possibleNamespace] . implode('/', $undefinedNamespaceFragments)); >$undefinedNamespaceFragments[] = array_pop($namespaceFragments); > return false; > > 

Довольно интересно, что, похоже, нет никакого метода отражения, который сделает это для вас. Однако я придумал небольшой класс, способный читать информацию о пространстве имен.

Читайте также:  Секреты css лии веру

Для этого вам нужно пройти через все определенные классы. Затем мы получаем пространство имен этого класса и храним его в массив вместе с самим именем класса.

 ClassOne include 'ClassOne/ClassOne.php'; // ClassOne namespaces -> ClassTwo include 'ClassTwo/ClassTwo.php'; include 'ClassTwo/ClassTwoNew.php'; // So now we have two namespaces defined // by ourselves (ClassOne -> contains 1 class, ClassTwo -> contains 2 classes) class NameSpaceFinder < private $namespaceMap = []; private $defaultNamespace = 'global'; public function __construct() < $this->traverseClasses(); > private function getNameSpaceFromClass($class) < // Get the namespace of the given class via reflection. // The global namespace (for example PHP's predefined ones) // will be returned as a string defined as a property ($defaultNamespace) // own namespaces will be returned as the namespace itself $reflection = new \ReflectionClass($class); return $reflection->getNameSpaceName() === '' ? $this->defaultNamespace : $reflection->getNameSpaceName(); > public function traverseClasses() < // Get all declared classes $classes = get_declared_classes(); foreach($classes AS $class) < // Store the namespace of each class in the namespace map $namespace = $this->getNameSpaceFromClass($class); $this->namespaceMap[$namespace][] = $class; > > public function getNameSpaces() < return array_keys($this->namespaceMap); > public function getClassesOfNameSpace($namespace) < if(!isset($this->namespaceMap[$namespace])) throw new \InvalidArgumentException('The Namespace '. $namespace . ' does not exist'); return $this->namespaceMap[$namespace]; > > $finder = new NameSpaceFinder(); var_dump($finder->getClassesOfNameSpace('ClassTwo')); 

array(2) < [0]=>string(17) «ClassTwo\ClassTwo» [1]=> string(20) «ClassTwo\ClassTwoNew» >

Конечно, все, кроме самого класса NameSpaceFinder, если оно собрано быстро и грязно. Поэтому не стесняйтесь очищать include беспорядок, используя автозагрузку.

Найти классы

Класс может быть локализован в файловой системе по имени и пространству имен, как это делает автозагрузчик. В нормальном случае пространство имен должно указывать относительный путь к файлам классов. Входящие пути являются отправными точками относительных путей. Функция get_include_path() возвращает список get_include_path() путей в одну строку. Каждый включенный путь может быть протестирован, существует ли относительный путь, который соответствует пространству имен. Если найден подходящий путь, вы узнаете расположение файлов классов.

Получить имена классов

Как только будет определено расположение файлов классов, классы могут быть извлечены из имен файлов, поскольку имя файла класса должно состоять из имени класса, за которым следует .php .

Образец кода

Вот пример кода, чтобы получить все имена классов пространства имен foo\bar в виде массива строк:

$namespace = 'foo\bar'; // Relative namespace path $namespaceRelativePath = str_replace('\\', DIRECTORY_SEPARATOR, $namespace); // Include paths $includePathStr = get_include_path(); $includePathArr = explode(PATH_SEPARATOR, $includePathStr); // Iterate include paths $classArr = array(); foreach ($includePathArr as $includePath) < $path = $includePath . DIRECTORY_SEPARATOR . $namespaceRelativePath; if (is_dir($path)) < // Does path exist? $dir = dir($path); // Dir handle while (false !== ($item = $dir->read())) < // Read next item in dir $matches = array(); if (preg_match('/^(?[^.].+)\.php$/', $item, $matches)) < $classArr[] = $matches['class']; >> $dir->close(); > > // Debug output var_dump($includePathArr); var_dump($classArr); 

Я приведу пример, который фактически используется в нашем приложении Laravel 5, но его можно использовать почти везде. В примере возвращаются имена классов с пространством имён, которые можно легко извлечь, если это не требуется.

Читайте также:  Подключение шрифтов css woff2

легенда

  • > – Путь для удаления из пути текущего файла, чтобы попасть в папку приложения
  • > – путь к папке из папки приложения, где существуют целевые классы
  • > – путь пространства имен

Код

$classPaths = glob(str_replace('>', '',__DIR__) .'>/*.php'); $classes = array(); $namespace = '>'; foreach ($classPaths as $classPath) < $segments = explode('/', $classPath); $segments = explode('\\', $segments[count($segments) - 1]); $classes[] = $namespace . $segments[count($segments) - 1]; > 

Люди Laravel могут использовать app_path() . ‘/>/*.php’ app_path() . ‘/>/*.php’ в glob ().

Я думаю, что у многих людей может быть такая проблема, поэтому я решил использовать ответы от @hpierce и @ loïc-faugeron для решения этой проблемы.

С описанным ниже классом вы можете иметь все классы в пространстве имен или соблюдать определенный термин.

getClassMap()); > > public function getClasses() < $allClasses = []; if (false === empty(self::$classes)) < foreach (self::$classes as $class) < $allClasses[] = '\\' . $class; >> return $allClasses; > public function getClassesByNamespace($namespace) < if (0 !== strpos($namespace, '\\')) < $namespace = '\\' . $namespace; >$termUpper = strtoupper($namespace); return array_filter($this->getClasses(), function($class) use ($termUpper) < $className = strtoupper($class); if ( 0 === strpos($className, $termUpper) and false === strpos($className, strtoupper('Abstract')) and false === strpos($className, strtoupper('Interface')) )< return $class; >return false; >); > public function getClassesWithTerm($term) < $termUpper = strtoupper($term); return array_filter($this->getClasses(), function($class) use ($termUpper) < $className = strtoupper($class); if ( false !== strpos($className, $termUpper) and false === strpos($className, strtoupper('Abstract')) and false === strpos($className, strtoupper('Interface')) )< return $class; >return false; >); > > 

В этом случае вы должны использовать Composer для выполнения автозагрузки классов. Используя доступную на нем ClassMap, решение упрощается.

Самый простой способ – использовать собственную функцию автозагрузчика __autoload и внутри нее сохранить загруженные имена классов. Это вам подходит?

В противном случае, я думаю, вам придется иметь дело с некоторыми методами отражения.

class_parents , spl_classes() и class_uses могут использоваться для извлечения всех имен классов

Вы можете использовать get_declared_classes но с небольшой дополнительной работой.

$needleNamespace = 'MyNamespace'; $classes = get_declared_classes(); $neededClasses = array_filter($classes, function($i) use ($needleNamespace) < return strpos($i, $needleNamespace) === 0; >); 

Поэтому сначала вы получаете все объявленные классы, а затем проверяете, какие из них начинаются с вашего пространства имен.

Примечание : вы получите массив, где ключи не начинаются с 0. Чтобы добиться этого, вы можете попробовать: array_values($neededClasses); ,

для symfony вы можете использовать компонент Finder:

Источник

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.

Allows you to list full qualified class names in directories and files.

License

WyriHaximus/php-list-classes-in-directory

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.

Читайте также:  Inspect and edit html life

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

List all PHP classes in directories and files

Latest Stable Version Total Downloads Code Coverage License

To install via Composer, use the command below, it will automatically detect the latest version and bind it with ^ .

composer require wyrihaximus/list-classes-in-directory 

get a list of classes from multiple directories.

use function WyriHaximus\listClassesInDirectories; use function WyriHaximus\listInstantiatableClassesInDirectories; use function WyriHaximus\listNonInstantiatableClassesInDirectories; // $classes now contains a list of full qualified class names from 'src/' and 'tests/' $classes = listClassesInDirectories( __DIR__ . '/src', __DIR__ . '/tests' ); // use listInstantiatableClassesInDirectories() or listNonInstantiatableClassesInDirectories() to only consider classes that can actually be instantiated, or not. $instantiatableClasses = listInstantiatableClassesInDirectory( __DIR__ . '/src', __DIR__ . '/tests' ); $nonInstantiatableClasses = listNonInstantiatableClassesInDirectory( __DIR__ . '/src', __DIR__ . '/tests' );

get a list of classes from one directory.

use function WyriHaximus\listClassesInDirectory; use function WyriHaximus\listInstantiatableClassesInDirectory; use function WyriHaximus\listNonInstantiatableClassesInDirectory; // $classes now contains a list of full qualified class names from __DIR__ $classes = listClassesInDirectory(__DIR__); // use listInstantiatableClassesInDirectory() or listNonInstantiatableClassesInDirectory() to only consider classes that can actually be instantiated, or not. $instantiatableClasses = listInstantiatableClassesInDirectory(__DIR__); $nonInstantiatableClasses = listNonInstantiatableClassesInDirectory(__DIR__);

get a list of classes from multiple files.

use function WyriHaximus\listClassesInFiles; // $classes now contains a list of full qualified class names from 'Bar.php' and 'Foo.php' $classes = listClassesInFiles( __DIR__ . '/Bar.php', __DIR__ . '/Foo.php' );

get a list of classes from one file.

use function WyriHaximus\listClassesInFile; // $classes now contains a list of full qualified class names from 'Foo.php' $classes = listClassesInFile(__DIR__.'/Foo.php');

This package is a shorthand function for using better reflection and is based on one of the examples .

Copyright (c) 2018 Cees-Jan Kiewiet

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the «Software»), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED «AS IS», WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

Allows you to list full qualified class names in directories and files.

Источник

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