PHPackages                             liquidrazor/class-locator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PSR &amp; Standards](/categories/psr-standards)
4. /
5. liquidrazor/class-locator

ActiveLibrary[PSR &amp; Standards](/categories/psr-standards)

liquidrazor/class-locator
=========================

Minimal deterministic class discovery and validation library for PHP 8.3+.

v0.1.2(2mo ago)011MITPHPPHP ^8.3

Since Mar 27Pushed 2mo agoCompare

[ Source](https://github.com/LiquidRazor/ClassLocator)[ Packagist](https://packagist.org/packages/liquidrazor/class-locator)[ Docs](https://github.com/LiquidRazor/ClassLocator)[ RSS](/packages/liquidrazor-class-locator/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (3)Versions (4)Used By (1)

LiquidRazor ClassLocator
========================

[](#liquidrazor-classlocator)

A minimal PHP 8.3+ library for deterministic class discovery and validation.

---

What it does
------------

[](#what-it-does)

- Uses `liquidrazor/file-locator` to discover PHP files
- Maps file paths → FQCN using PSR-4 rules
- Validates that your codebase matches its declared structure
- Exposes structural symbol metadata from declared symbols when declaration validation runs

That’s it.

---

Philosophy
----------

[](#philosophy)

- Filesystem is truth
- Deterministic mapping over guesswork
- Validation is explicit, not implicit
- No magic, no hidden loading
- Built for real-world broken projects

---

Dependency Model
----------------

[](#dependency-model)

ClassLocator is built on top of:

- `liquidrazor/file-locator`

It does NOT define roots.
It consumes whatever FileLocator provides.

---

Namespace Resolution
--------------------

[](#namespace-resolution)

ClassLocator does NOT detect namespaces for discovery.

Instead:

1. Namespace roots are loaded from the target project's `composer.json` (PSR-4)
2. File paths are mapped deterministically to expected FQCN
3. Namespace parsing is used for validation and structural metadata extraction when enabled by mode

Filesystem + Composer define expectation.
Files must comply.

---

Modes
-----

[](#modes)

### ENFORCING (default)

[](#enforcing-default)

- Requires valid Composer PSR-4 mappings
- Validates all files
- Extracts structural metadata from declared symbols
- Throws on critical violations
- Fails fast on broken structure

### STRICT

[](#strict)

- Validates all files
- Extracts structural metadata from declared symbols
- Collects violations
- Does not throw

### LENIENT

[](#lenient)

- Best-effort discovery
- Skips invalid entries
- Skips declaration validation
- Returns unresolved structural metadata instead of guessing

---

Validation
----------

[](#validation)

Validation compares:

expected (path + composer)
vs
actual (file namespace + symbol)

### Detects:

[](#detects)

- Namespace mismatch
- Class/interface/trait/enum mismatch
- Files outside PSR-4 scope
- Duplicate FQCN
- Missing or invalid Composer mappings

---

Usage
-----

[](#usage)

```
$fileLocator = new FileLocator(...);

$classLocator = new ClassLocator($fileLocator, Mode::STRICT);

$result = $classLocator->locate();
```

---

Public API
----------

[](#public-api)

### ClassLocator

[](#classlocator)

```
new ClassLocator(FileLocator $fileLocator, Mode $mode = Mode::ENFORCING)
```

```
LocateResult locate()
```

### Mode (enum)

[](#mode-enum)

```
Mode::ENFORCING
Mode::STRICT
Mode::LENIENT
```

### LocateResult

[](#locateresult)

```
array getClasses()
array getViolations()
bool hasViolations()
```

### SymbolKind (enum)

[](#symbolkind-enum)

```
SymbolKind::CLASS_
SymbolKind::INTERFACE
SymbolKind::TRAIT
SymbolKind::ENUM
```

`SymbolKind::CLASS_` uses a trailing underscore because `CLASS` collides with PHP's `::class` constant syntax.

### ClassInfo

[](#classinfo)

```
string getFqcn()
string getPath()
?SymbolKind getSymbolKind()
array getImplementedInterfaces()
?string getParentClass()
?bool isAbstract()
?bool isFinal()
bool hasResolvedMetadata()
```

In `ENFORCING` and `STRICT`, `ClassInfo` metadata is derived from the declared symbol in the source file.

In `LENIENT`, declaration parsing is skipped, so:

- `getSymbolKind()` returns `null`
- `getImplementedInterfaces()` returns `[]`
- `getParentClass()` returns `null`
- `isAbstract()` returns `null`
- `isFinal()` returns `null`
- `hasResolvedMetadata()` returns `false`

### Violation

[](#violation)

```
string getMessage()
string getPath()
```

---

Example: Inspect Structural Metadata
------------------------------------

[](#example-inspect-structural-metadata)

```
$fileLocator = new FileLocator(...);
$classLocator = new ClassLocator($fileLocator, Mode::STRICT);

$result = $classLocator->locate();

foreach ($result->getClasses() as $classInfo) {
    if (!$classInfo->hasResolvedMetadata()) {
        continue;
    }

    if ($classInfo->getSymbolKind() !== SymbolKind::CLASS_) {
        continue;
    }

    if (in_array('App\\Contract\\EventSubscriber', $classInfo->getImplementedInterfaces(), true)) {
        // Downstream code can classify this symbol without re-parsing the file.
    }
}
```

---

Responsibility Boundary
-----------------------

[](#responsibility-boundary)

ClassLocator exposes structural symbol metadata.

It still does NOT:

- classify framework concepts
- register services
- detect event semantics
- manipulate autoloading
- execute discovered files

Downstream tools may use the exposed metadata for their own classification or validation logic.

---

Summary
-------

[](#summary)

Give it a FileLocator.

It gives you deterministic classes, structural violations, and source-derived symbol metadata when validation is enabled.

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance84

Actively maintained with recent releases

Popularity1

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

3

Last Release

83d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/4306922?v=4)[Noramarth](/maintainers/Noramarth)[@Noramarth](https://github.com/Noramarth)

---

Top Contributors

[![Noramarth](https://avatars.githubusercontent.com/u/4306922?v=4)](https://github.com/Noramarth "Noramarth (3 commits)")

---

Tags

phpcomposervalidationPSR-4class-locatorclass-discovery

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/liquidrazor-class-locator/health.svg)

```
[![Health](https://phpackages.com/badges/liquidrazor-class-locator/health.svg)](https://phpackages.com/packages/liquidrazor-class-locator)
```

###  Alternatives

[icamys/php-sitemap-generator

Simple PHP sitemap generator.

175356.9k7](/packages/icamys-php-sitemap-generator)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
