adachsoft / php-code-reader
Static PHP source code reader for inspecting classes, interfaces, traits, enums, types, and metadata without loading user code.
Requires
- php: >=8.2
- adachsoft/normalized-safe-path: ^0.1.0
- nikic/php-parser: ^5.0
Requires (Dev)
- adachsoft/php-code-style: ^0.7
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^13.0
- rector/rector: ^2.6
- symplify/phpstan-rules: ^14.13
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A small PHP library for static code reading without executing user code, without runtime reflection in the public API and without exposing the underlying AST structures.
Designed to read PHP source files from external repositories — classes do not need to be loaded by the current PHP process autoloader.
Requirements
- PHP >= 8.2
nikic/php-parseras runtime dependency
Installation
composer require adachsoft/php-code-reader
Quick Start
use AdachSoft\PhpCodeReader\CodeReaderFactory;
use AdachSoft\PhpCodeReader\ReadOptionsDto;
use AdachSoft\PhpCodeReader\VisibilityEnum;
$factory = new CodeReaderFactory();
// Base path defines the sandbox for readable files (must be an existing, readable directory).
// Point it to the root of the external repository you want to read.
$reader = $factory->create('/path/to/external/repo/src');
// Read all classes from a file
$fileDto = $reader->readFile('Some/Subdirectory/SomeClass.php');
// Read a single class by its fully-qualified name.
// The class does NOT need to be loaded by the autoloader — the library resolves
// FQCN to file path by scanning and parsing PHP files in the base directory.
$classFileDto = $reader->readClass('App\SomeNamespace\SomeClass');
// With options: filter by visibility and include inherited members
$options = new ReadOptionsDto(
visibilityMask: VisibilityEnum::PUBLIC->value | VisibilityEnum::PROTECTED->value,
includeInheritance: true,
);
$classFileDto = $reader->readClass('App\SomeNamespace\SomeClass', $options);
How It Works
CodeReaderFactory::create($basePath)validates and resolves the base directory. All file reads are sandboxed to this path — traversal outside it is rejected.readFile()parses the given PHP file using a static AST parser (nikic/php-parser) and returns aPhpFileDtowith all class-like structures found in it: classes, interfaces, traits, and enums.readClass()scans all.phpfiles under the base path, builds an in-memoryFQCN → filemap using AST parsing, then delegates toreadFile(). Noclass_exists()orReflectionClassis used at any point.- When
includeInheritance: trueis set, parent classes and used traits are also resolved from the same FQCN map, enabling full inheritance merging without autoloading. - Method signatures, promoted constructor properties, property types, class constant types, default values, and declaration modifiers are read from native PHP syntax. Imported and aliased class names are resolved to FQCNs, while built-in and global types remain unprefixed.
Returned DTOs
| DTO | Description |
|---|---|
PhpFileDto | Top-level result: primary fqcn, filePath, namespace, and list of class-like declarations found in the file. |
PhpClassDto | Class-like metadata: short name, fqcn, filePath, ClassTypeEnum, modifiers, extends, implements, used traits, methods, properties, and constants. |
PhpMethodDto | Method metadata: name, visibility, declaring class, static/abstract/final flags, parameters, return type, and inheritance state. |
PhpParameterDto | Parameter metadata: type, nullability, variadic and promoted-property flags, default value, visibility, and readonly state. |
PhpPropertyDto | Property metadata: name, visibility, declaring class, static/readonly/promoted flags, type, default value, and inheritance state. |
PhpConstDto | Class or enum constant metadata: name, visibility, declaring class, type, value, and final flag. |
Class-like Structures and Metadata
PhpClassDto represents every supported class-like declaration. Its type property contains one of the following ClassTypeEnum values:
ClassTypeEnum::CLASS_for classes,ClassTypeEnum::INTERFACEfor interfaces,ClassTypeEnum::TRAITfor traits,ClassTypeEnum::ENUMfor enums.
Class metadata includes isFinal, isAbstract, isReadonly, extends, implements, and uses. Enum cases are exposed through the constants collection.
Method parameters preserve normalized type information, including union and intersection types, nullability, variadic status, default values, and constructor property promotion. Promoted parameters are represented both in the constructor method parameters and in the class properties with isPromoted: true.
DTO Serialization
All public DTOs expose toArray() for stable data serialization.
The serialized payload uses snake_case keys. Nested methods, parameters, properties, and constants are serialized recursively.
Example PhpFileDto::toArray() output
[
'fqcn' => 'App\\SomeNamespace\\SomeClass',
'file_path' => '/path/to/external/repo/src/Some/Subdirectory/SomeClass.php',
'namespace' => 'App\\SomeNamespace',
'classes' => [
[
'name' => 'SomeClass',
'fqcn' => 'App\\SomeNamespace\\SomeClass',
'file_path' => '/path/to/external/repo/src/Some/Subdirectory/SomeClass.php',
'type' => 'class',
'is_final' => false,
'is_abstract' => false,
'is_readonly' => false,
'extends' => null,
'implements' => [],
'uses' => [],
'methods' => [
[
'name' => 'someMethod',
'visibility' => 'public',
'declared_in' => 'App\\SomeNamespace\\SomeClass',
'is_static' => false,
'is_abstract' => false,
'is_final' => false,
'is_inherited' => false,
'parameters' => [
[
'name' => 'foo',
'type' => 'string',
'is_nullable' => false,
'is_variadic' => false,
'is_promoted' => false,
'has_default' => false,
'default_value' => null,
'visibility' => null,
'is_readonly' => false,
],
[
'name' => 'bar',
// FQCN for class-typed parameters
'type' => 'App\\SomeNamespace\\SomeDependency',
'is_nullable' => false,
'is_variadic' => false,
'is_promoted' => false,
'has_default' => false,
'default_value' => null,
'visibility' => null,
'is_readonly' => false,
],
],
// Scalar or FQCN return type, when declared
'return_type' => 'App\\SomeNamespace\\ResultDto',
],
],
'properties' => [
[
'name' => 'someProperty',
'visibility' => 'public',
'declared_in' => 'App\\SomeNamespace\\SomeClass',
'is_static' => true,
'is_readonly' => false,
'is_promoted' => false,
'has_default' => false,
'is_inherited' => false,
// Scalar or FQCN property type, when declared
'type' => 'int',
'default_value' => null,
],
],
'constants' => [
[
'name' => 'SOME_CONST',
'visibility' => 'public',
'declared_in' => 'App\\SomeNamespace\\SomeClass',
// Scalar or FQCN constant type, when declared
'type' => 'string',
'value' => 'example',
'is_final' => false,
],
],
],
],
]
Notes
readClass()accepts a plainstringFQCN (without leading backslash). The declaration does not need to exist in the current PHP process.readFile()andreadClass()support classes, interfaces, traits, and enums.- Static, abstract, final, readonly, inherited, and promoted-member metadata is included where applicable.
- Types of method parameters, return types, properties, and class constants are read from native type declarations when present.
- Union, intersection, nullable, built-in, global, imported, and aliased types are normalized without incorrectly prefixing namespaces.
- The default
ReadOptionsDtovisibility mask includes public, protected, and private members; usevisibilityMaskto restrict it. - The public API never returns AST nodes.
CodeReaderinstances must be created viaCodeReaderFactory::create().- File security: symlinks and path traversal sequences that resolve outside the configured base path are rejected.