You can simply scan a string, a file or a full directory and you can see a simple data structure from your php code.
- Classes (PHPClass)
- Properties (PHPProperty)
- Constants (PHPConst)
- Methods (PHPMethod)
- Interfaces (PHPInterface)
- Traits (PHPTrait)
- Enums (PHPEnum)
- Functions (PHPFunction)
- Parameter (PHPParameter)
- Attributes (PHPAttribute)
This code is forked from JetBrains/phpstorm-stubs but you can't use the classes from "phpstorm-stubs" directly, because they are in a test namespace and the autoloader is "autoload-dev", so here is a extended version.
We will use:
- PHP >= 8.1
Runtime support for this library is PHP 8.1+, while the parser test suite validates analyzable source syntax from PHP 5.3 through PHP 8.5.
| Source Syntax Generation | Representative coverage |
|---|---|
| PHP 5.3 | namespaces, closures with use, array() syntax |
| PHP 5.4 | traits, callable, short arrays |
| PHP 5.5 | generators / yield, finally |
| PHP 5.6 | variadics, argument unpacking-ready syntax, constant arrays |
| PHP 7.0 | scalar parameter types, return types, anonymous classes |
| PHP 7.1 | nullable types, iterable, void |
| PHP 7.2 | object type |
| PHP 7.3 | trailing commas in calls |
| PHP 7.4 | typed properties, arrow functions |
| Feature | PHP Version | Supported |
|---|---|---|
| Attributes (class, method, property, parameter, constant) | 8.0+ | ✅ |
| Constructor property promotion | 8.0+ | ✅ |
| Union types | 8.0+ | ✅ |
| Named arguments | 8.0+ | ✅ |
| Match expressions | 8.0+ | ✅ |
| Nullsafe operator | 8.0+ | ✅ |
| Enums (unit, string-backed, int-backed) | 8.1+ | ✅ |
| Readonly properties | 8.1+ | ✅ |
| Intersection types | 8.1+ | ✅ |
never return type |
8.1+ | ✅ |
| First-class callable syntax | 8.1+ | ✅ |
| Readonly classes | 8.2+ | ✅ |
| DNF types | 8.2+ | ✅ |
Standalone true, false, null types |
8.2+ | ✅ |
| Trait constants | 8.2+ | ✅ |
| Typed class constants | 8.3+ | ✅ |
#[\Override] attribute detection |
8.3+ | ✅ |
| Property hooks / asymmetric visibility | 8.4+ | ✅ |
composer require voku/simple-php-code-parserParse a string:
$code = '
<?php
namespace voku\tests;
class SimpleClass {}
$obja = new class() {};
$objb = new class {};
class AnotherClass {}
';
$phpCode = \voku\SimplePhpParser\Parsers\PhpCodeParser::getFromString($code);
$phpClasses = $phpCode->getClasses();
var_dump($phpClasses['voku\tests\SimpleClass']); // "PHPClass"-objectParse one class:
$phpCode = \voku\SimplePhpParser\Parsers\PhpCodeParser::getFromClassName(Dummy::class);
$phpClasses = $phpCode->getClasses();
var_dump($phpClasses[Dummy::class]); // "PHPClass"-object
var_dump($phpClasses[Dummy::class]->methods); // "PHPMethod[]"-objects
var_dump($phpClasses[Dummy::class]->methods['withoutPhpDocParam']); // "PHPMethod"-object
var_dump($phpClasses[Dummy::class]->methods['withoutPhpDocParam']->parameters); // "PHPParameter[]"-objects
var_dump($phpClasses[Dummy::class]->methods['withoutPhpDocParam']->parameters['useRandInt']); // "PHPParameter"-object
var_dump($phpClasses[Dummy::class]->methods['withoutPhpDocParam']->parameters['useRandInt']->type); // "bool"Parse one file:
$phpCode = \voku\SimplePhpParser\Parsers\PhpCodeParser::getPhpFiles(__DIR__ . '/Dummy.php');
$phpClasses = $phpCode->getClasses();
var_dump($phpClasses[Dummy::class]); // "PHPClass"-object
var_dump($phpClasses[Dummy::class]->methods); // "PHPMethod[]"-objects
var_dump($phpClasses[Dummy::class]->methods['withoutPhpDocParam']); // "PHPMethod"-object
var_dump($phpClasses[Dummy::class]->methods['withoutPhpDocParam']->parameters); // "PHPParameter[]"-objects
var_dump($phpClasses[Dummy::class]->methods['withoutPhpDocParam']->parameters['useRandInt']); // "PHPParameter"-object
var_dump($phpClasses[Dummy::class]->methods['withoutPhpDocParam']->parameters['useRandInt']->type); // "bool"Parse many files:
$phpCode = \voku\SimplePhpParser\Parsers\PhpCodeParser::getPhpFiles(__DIR__ . '/src');
$phpClasses = $phpCode->getClasses();
var_dump($phpClasses[Dummy::class]); // "PHPClass"-objectUnified metadata API:
$phpCode = \voku\SimplePhpParser\Parsers\PhpCodeParser::getPhpFiles(__DIR__ . '/src');
$phpClasses = $phpCode->getClasses();
$phpInterfaces = $phpCode->getInterfaces();
$phpTraits = $phpCode->getTraits();
$phpEnums = $phpCode->getEnums();
$phpFunctions = $phpCode->getFunctions();
$phpConstants = $phpCode->getConstants();
$functionInfo = $phpCode->getFunctionsInfo();
$methodInfo = $phpClasses[MyService::class]->getMethodsInfo();
$propertyInfo = $phpClasses[MyService::class]->getPropertiesInfo();Every parsed model element exposes its inclusive source range. This lets an
indexer store a compact symbol map and later read exactly one declaration with
sed (or a byte-range read), instead of sending a whole file to a coding
agent.
$phpCode = \voku\SimplePhpParser\Parsers\PhpCodeParser::getPhpFiles(__DIR__ . '/src/MyService.php');
$method = $phpCode->getClasses()[MyService::class]->methods['handle'];
// 1-based, inclusive line range for: sed -n "{$method->line},{$method->endLine}p" …
echo $method->line;
echo $method->endLine;
// 0-based, inclusive byte range in the parsed source file.
echo $method->startFilePos;
echo $method->endFilePos;Class-like models also expose directly composed traits as fully-qualified
names in $traitUses, plus alias and insteadof rules in
$traitAdaptations. Interfaces retain every declared parent interface.
For syntax that deliberately remains outside the compact Model API, use the same names-resolved php-parser AST that builds it:
$ast = \voku\SimplePhpParser\Parsers\PhpCodeParser::getAstFromFile(__DIR__ . '/src/MyService.php');
// or: PhpCodeParser::getAstFromString($source);The returned nodes have source-location attributes and parent references.
Resolvable names are fully-qualified; their original aliases remain available
through php-parser's originalName node attribute. Parent references make the
AST cyclic, so it should be inspected rather than serialized directly.
For an even smaller file-header summary, use PHPFileInfo:
$fileInfo = \voku\SimplePhpParser\Parsers\PhpCodeParser::getFileInfoFromFile(__DIR__ . '/src/MyService.php');
// Each namespace scope contains imports (class/function/const aliases) and
// declare values such as strict_types, with their source lines.
foreach ($fileInfo->namespaces as $namespace) {
var_dump($namespace['name'], $namespace['imports'], $namespace['declares']);
}Import-aware PHPDoc fields preserve the old rendered fields and add precise
typeFromPhpDocResolved / returnTypeFromPhpDocResolved values. Thus
use Vendor\Payload as Message; can resolve @param Message $message to
\Vendor\Payload without changing legacy output. Function and method models
also expose documented exception types in $throws, is_returned_by_ref, and
(for methods) is_abstract; parameters expose is_promoted. PHPEnum keeps
its legacy $cases value map and additionally exposes source-aware,
attribute-aware case objects in $caseDetails.
The library is meant to be the simple integration layer that other tools can call instead of wiring together nikic/php-parser, phpstan/phpdoc-parser, phpDocumentor, and native reflection themselves. The test suite validates analyzable PHP source from PHP 5.3 through PHP 8.5, including legacy syntax generations and modern type declarations / metadata such as attributes, enums, readonly constructs, typed constants, and property hooks.
Access enums:
$phpCode = \voku\SimplePhpParser\Parsers\PhpCodeParser::getPhpFiles(__DIR__ . '/src');
$phpEnums = $phpCode->getEnums();
// PHPEnum objects with scalarType, cases, methods, constants, attributesAccess attributes:
$phpCode = \voku\SimplePhpParser\Parsers\PhpCodeParser::getPhpFiles(__DIR__ . '/src');
$phpClasses = $phpCode->getClasses();
$class = $phpClasses['MyClass'];
// Class-level attributes
foreach ($class->attributes as $attr) {
echo $attr->name; // e.g. "MyAttribute"
print_r($attr->arguments); // constructor arguments (array)
}
// Method/property/parameter attributes work the same way
foreach ($class->methods['myMethod']->attributes as $attr) { ... }
foreach ($class->properties['myProp']->attributes as $attr) { ... }
foreach ($class->methods['myMethod']->parameters['param']->attributes as $attr) { ... }For support and donations please visit GitHub | Issues | PayPal | Patreon.
For status updates and release announcements please visit Releases | Patreon.
For professional support please contact me.
- Thanks to GitHub (Microsoft) for hosting the code and a good infrastructure including Issues-Management, etc.
- Thanks to IntelliJ as they make the best IDEs for PHP and they gave me an open source license for PhpStorm!
- Thanks to PHPStan && Psalm for really great Static analysis tools and for discover bugs in the code!