Search by

adachsoft / php-code-reader

Arkadiusz Adach

Static PHP source code reader for inspecting classes, interfaces, traits, enums, types, and metadata without loading user code.

Package info

gitlab.com/a.adach/php-code-reader

Issues

pkg:composer/adachsoft/php-code-reader

Statistics

Installs: 26

Dependents: 1

Suggesters: 0

Stars: 0

v0.6.0 2026-09-07 11:02 UTC

This package is auto-updated.

Last update: 2026-09-07 09:03:27 UTC


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-parser as 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

  1. CodeReaderFactory::create($basePath) validates and resolves the base directory. All file reads are sandboxed to this path — traversal outside it is rejected.
  2. readFile() parses the given PHP file using a static AST parser (nikic/php-parser) and returns a PhpFileDto with all class-like structures found in it: classes, interfaces, traits, and enums.
  3. readClass() scans all .php files under the base path, builds an in-memory FQCN → file map using AST parsing, then delegates to readFile(). No class_exists() or ReflectionClass is used at any point.
  4. When includeInheritance: true is set, parent classes and used traits are also resolved from the same FQCN map, enabling full inheritance merging without autoloading.
  5. 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

DTODescription
PhpFileDtoTop-level result: primary fqcn, filePath, namespace, and list of class-like declarations found in the file.
PhpClassDtoClass-like metadata: short name, fqcn, filePath, ClassTypeEnum, modifiers, extends, implements, used traits, methods, properties, and constants.
PhpMethodDtoMethod metadata: name, visibility, declaring class, static/abstract/final flags, parameters, return type, and inheritance state.
PhpParameterDtoParameter metadata: type, nullability, variadic and promoted-property flags, default value, visibility, and readonly state.
PhpPropertyDtoProperty metadata: name, visibility, declaring class, static/readonly/promoted flags, type, default value, and inheritance state.
PhpConstDtoClass 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::INTERFACE for interfaces,
  • ClassTypeEnum::TRAIT for traits,
  • ClassTypeEnum::ENUM for 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 plain string FQCN (without leading backslash). The declaration does not need to exist in the current PHP process.
  • readFile() and readClass() 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 ReadOptionsDto visibility mask includes public, protected, and private members; use visibilityMask to restrict it.
  • The public API never returns AST nodes.
  • CodeReader instances must be created via CodeReaderFactory::create().
  • File security: symlinks and path traversal sequences that resolve outside the configured base path are rejected.