https://github.com/decodelabs/archetype
Simple class name resolution for PHP
https://github.com/decodelabs/archetype
class-loader php resolver
Last synced: 6 months ago
JSON representation
Simple class name resolution for PHP
- Host: GitHub
- URL: https://github.com/decodelabs/archetype
- Owner: decodelabs
- License: mit
- Created: 2021-11-17T15:25:57.000Z (over 4 years ago)
- Default Branch: develop
- Last Pushed: 2025-04-14T11:30:12.000Z (about 1 year ago)
- Last Synced: 2025-04-15T14:06:42.529Z (about 1 year ago)
- Topics: class-loader, php, resolver
- Language: PHP
- Homepage:
- Size: 147 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Archetype
[](https://packagist.org/packages/decodelabs/archetype)
[](https://packagist.org/packages/decodelabs/archetype)
[](https://packagist.org/packages/decodelabs/archetype)
[](https://github.com/decodelabs/archetype/actions/workflows/integrate.yml)
[](https://github.com/phpstan/phpstan)
[](https://packagist.org/packages/decodelabs/archetype)
### Simple class name resolution for PHP
Archetype provides a generic frontend to resolving implementation classes for a named interface with an extensible plugin architechture.
---
## Installation
This package requires PHP 8.4 or higher.
Install via Composer:
```bash
composer require decodelabs/archetype
```
## Usage
Use `Archetype` when designing plugin oriented libraries that need to load arbitrary extension classes based on a naming convention.
By mapping names to classes in an extensible and customisable resolver structure, `Archetype` allows fast and reliable means to create loosely coupled plugin ecosystems.
```php
use DecodeLabs\Archetype;
use MyInterface;
$archetype = new Archetype();
$class = $archetype->resolve(MyInterface::class, 'MyClass');
```
It is especially useful in `Factory` patterns where you need to load arbitrary classes based on a name.
Example:
```php
// Main library
namespace My\Library
{
use DecodeLabs\Archetype;
interface Thing {}
class Factory {
public function __construct(
private Archetype $archetype
) {
$this->archetype = $archetype;
}
public function loadThing(
string $name
): Thing {
// Resolve name to class for Thing interface
$class = $this->archetype->resolve(Thing::class, $name);
return new $class();
}
}
}
// Thing implementations
namespace My\Library\Thing
{
use My\Library\Thing;
class Box implements Thing {}
class Potato implements Thing {}
class Dog implements Thing {}
}
// Calling code
namespace My\App
{
use My\Library\Factory;
$factory = new Factory(new Archetype());
$box = $factory->loadThing('Box');
$potato = $factory->loadThing('Potato');
$dog = $factory->loadThing('Dog');
}
```
## Resolvers
Archetype uses a hierarchy of `Resolvers` to turn a name into a class. By default, the `Handler` will fall back on a generic resolver that simply locates the named class within the namespace of the associated interface.
In the above example, the implementations of the `My\Library\Thing` can be found at `My\Library\Thing\\*`.
### Custom resolvers
The `Resolver\Archetype` implementation however will also automatically look for custom `Resolver` classes in the same location as the target interface, named `\Archetype`.
The following example will replace the default functionality and cause Archetype to look in a different location for the `Thing` implementations:
```php
namespace My\Library {
use DecodeLabs\Archetype\Resolver;
class ThingArchetype implements Resolver
{
public function getInterface(): string
{
return Thing::class;
}
public function getPriority(): int
{
return 10;
}
public function resolve(string $name): ?string
{
return 'Some\\Other\\Namespace\\'.$name;
}
}
}
```
### Multiple resolvers
Multiple `Resolver` instances can be stacked against a single interface, called in series based on the priority they request, the first one to return a non-null class name wins.
Alternative `Resolvers` can be loaded with:
```php
use My\Library\Resolver\Alternative as AlternativeResolver;
$archetype = new Archetype();
$archetype->register(new AlternativeResolver());
```
### Class scanning
Some resolvers (including the default one) can scan and list all classes resolvable under a namespace.
```php
foreach($archetype->scanClasses(Thing::class) as $path => $class) {
echo 'Found class: '.$class.' at '.$path.PHP_EOL;
}
```
### File lookup
`Resolvers` that also implement the `Finder` interface can define the means to lookup a file path based on the provided name, against the space defined by the target interface.
This can be useful when the _space_ that is defined by the root interface may contain assets aside from PHP code.
It is down to the implementation to decide how to map names to file paths (there are no pre-built default `Finder` classes).
Example:
```php
namespace My\Library {
use DecodeLabs\Archetype\Finder;
class ThingArchetype implements Finder
{
public function getInterface(): string
{
return Thing::class;
}
public function getPriority(): int
{
return 10;
}
public function resolve(
string $name
): ?string {
return 'Some\\Other\\Namespace\\'.$name;
}
public function findFile(
string $name
): ?string {
return './some/other/namespace/'.$name.'.jpg';
}
}
}
namespace My\App {
use My\Library\Thing;
$boxImagePath = $archetype->findFile(Thing::class, 'box');
}
```
## Licensing
Archetype is licensed under the MIT License. See [LICENSE](./LICENSE) for the full license text.