moto / autoload
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 5
Watchers: 2
Forks: 0
Open Issues: 1
pkg:composer/moto/autoload
Requires
- php: ^8.4
Requires (Dev)
- pds/composer-script-names: ^1.0
- pds/skeleton: ^1.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
This package is not auto-updated.
Last update: 2025-10-15 14:21:00 UTC
README
This project defines a name-to-file resolution algorithm for autoloaders that allows more-than-one class per file.
Theory of Operation
One Class Per File
Historically, PHP class-to-file naming conventions have supported only one class per file.
Horde/PEAR
In the pre-namespacing versions of PHP, the original Horde/PEAR resolution logic converted underscores to directory separators to generate a file path:
Foo_Bar_Baz_Dib => /classes/Foo/Bar/Baz/Dib.php
Foo_Bar_Baz_Dib_Zim => /classes/Foo/Bar/Baz/Dib/Zim.php
PSR-0
PSR-0 modified this logic to recognized the formal namespaces introduced in PHP 5.3, so that ...
- namespace separators were converted to directory separators, and
- underscores only in the terminating class name portion were converted to directory separators:
Foo_Bar\Baz\Dib => /classes/Foo_Bar/Baz/Dib.php
Foo_Bar\Baz\Dib_Zim => /classes/Foo_Bar/Baz/Dib/Zim.php
PSR-4
PSR-4 modified PSR-0 so that ...
- underscores in the terminating class name portion would no longer be converted to directory separators, and
- a namespace prefix could be mapped to a directory prefix:
/**
* Foo_Bar\Baz\ maps to /classes/foo-bar/baz/src/
*/
Foo_Bar\Baz\Dib => /classes/foo-bar/baz/src/Dib.php
Foo_Bar\Baz\Dib_Zim => /classes/foo-bar/baz/src/Dib_Zim.php
More-Than-One Class Per File
The Moto name-to-file resolution algorithm modifies this even further, so that everything after an underscore in the terminating class name portion is ignored:
/**
* Foo_Bar\Baz\ maps to /classes/foo-bar/baz/src/
*/
Foo_Bar\Baz\Dib => /classes/foo-bar/baz/src/Dib.php
Foo_Bar\Baz\Dib_Zim => /classes/foo-bar/baz/src/Dib.php
Foo_Bar\Baz\Dib_Gir => /classes/foo-bar/baz/src/Dib.php
Foo_Bar\Baz\Dib_Irk => /classes/foo-bar/baz/src/Dib.php
This means the Dib.php file can contain any number of underscore-suffixed classes so long as they are prefixed with Dib ...
// /classes/foo-bar/src/Baz/Dib.php namespace Foo_Bar/Baz; class Dib { } class Dib_Zim { } class Dib_Gir { } class Dib_Irk { }
... and a Moto-compliant resolver will find the correct file for that class.
Resolution Algorithm
Given ...
-
a
namespace-prefixof a non-empty namespace (including the rightmost namespace separator) or an empty string (indicating the global namespace), and -
an absolute
directory-prefixfor thenamespace-prefix(including the rightmost directory separator)
... the following algorithm resolves a fully-qualified-name to an absolute-file-path or to null:
-
If the
fully-qualified-namedoes not begin with thenamespace-prefix, thefully-qualified-nameresolves tonull. -
Otherwise, set the
qualified-nameby capturing all characters after thenamespace-prefix. -
If the
qualified-namecontains a namespace separator ...A. Set the
partial-namespaceby capturing all characters up to and including the rightmost namespace separator, and set thepartial-nameby capturing all characters after the rightmost namespace separator.B. Otherwise, set the
partial-namespaceto an empty string, and set thepartial-nameto thequalified-name. -
If the
partial-namecontains an underscore, remove the first underscore and all characters thereafter. -
If the
partial-nameis empty, thefully-qualified-nameresolves tonull. -
Otherwise, set the
partial-directoryby converting each namespace separator in thepartial-namespaceto aDIRECTORY_SEPARATOR. -
Set the
absolute-file-pathby concatenating thedirectory-prefix,partial-directory,partial-name, and afilename-suffix(typically.php). -
If the
absolute-file-pathexists, thefully-qualified-nameresolves to theabsolute-file-path; otherwise, it resolves tonull.
Cf. the reference implementation resolutionAlgotrithm() method for an example.
Implications
-
Directory names with underscores WILL be resolvable.
-
Base file names with underscores WILL NOT be resolvable.
-
PSR-4 mapped classes without underscores are Moto-compatible.
-
The
partial-nameitself does not have to exist at theabsolute-file-path; that is, the file might contain only underscore-suffixed names:// Foo_Bar\Baz => /vendor/foo-bar/baz/src/Dib.php namespace Foo_Bar\Baz; // no Dib {} class class Dib_Zim {} class Dib_Gir {} class Dib_Irk {}
-
If function autoloading becomes supported by PHP, the Moto name-to-file resolution algorithm can support multiple functions per file:
// Foo_Bar\Baz => /vendor/foo-bar/baz/src/dib.php namespace Foo_Bar\Baz; function dib() {} function dib_zim() {} function dib_gir() {} function dib_irk() {}