{
    "href": "/post/2025/07/23/more-than-one-class-per-file/",
    "relId": "2025/07/23/more-than-one-class-per-file",
    "title": "More-Than-One Class Per File",
    "author": "pmjones",
    "tags": [
        {
            "href": "/tag/programming/",
            "relId": "programming",
            "title": "Programming",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/php/",
            "relId": "php",
            "title": "PHP",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/interop/",
            "relId": "interop",
            "title": "Interop",
            "author": null,
            "created": "2025-02-03 20:11:59 UTC",
            "updated": [
                "2025-02-03 20:11:59 UTC"
            ],
            "markup": "markdown"
        }
    ],
    "created": "2025-07-23 13:11:24 UTC",
    "updated": [
        "2025-07-23 13:11:24 UTC",
        "2025-07-23 13:22:27 UTC",
        "2025-07-23 13:22:33 UTC"
    ],
    "markup": "markdown",
    "html": "<p>In <a href=\"https://externals.io/message/128060#128085\">this PHP internals message</a> we read:</p>\n<blockquote>\n<p>I have participated in some internals discussions that point out a fact from the other direction: PHP makes no imposition about file structure. 1-class-per-file is strictly a PSR-4 implementation of a custom autoloader which we have gotten used to for so long. I would really love to be able to declare small related classes/interfaces in a single file ...</p>\n</blockquote>\n<p>There is something to be said for more-than-one class per file, and after a few evenings of tinkering, I can now present the <a href=\"https://github.com/motophp/autoload\">moto/autoload</a> package.</p>\n<p>The Moto name-to-file <a href=\"#resolution-algorithm\">resolution algorithm</a> is an ideological descendant from Horde/PEAR through PSR-0 and PSR-4, with the latest evolution being that everything after an underscore in the terminating class name portion is ignored:</p>\n<pre><code>/**\n * Foo_Bar\\Baz\\ maps to /classes/foo-bar/baz/src/\n */\nFoo_Bar\\Baz\\Dib     =&gt; /classes/foo-bar/baz/src/Dib.php\nFoo_Bar\\Baz\\Dib_Zim =&gt; /classes/foo-bar/baz/src/Dib.php\nFoo_Bar\\Baz\\Dib_Gir =&gt; /classes/foo-bar/baz/src/Dib.php\nFoo_Bar\\Baz\\Dib_Irk =&gt; /classes/foo-bar/baz/src/Dib.php\n</code></pre>\n<p>This means the <code>Dib.php</code> file can contain any number of underscore-suffixed classes so long as they are prefixed with <code>Dib</code> ...</p>\n<pre><code class=\"language-php\">// /classes/foo-bar/src/Baz/Dib.php\nnamespace Foo_Bar/Baz;\n\nclass Dib { }\n\nclass Dib_Zim { }\n\nclass Dib_Gir { }\n\nclass Dib_Irk { }\n</code></pre>\n<p>... and a Moto-compliant resolver will find the correct file for that class.</p>\n<p>And if function autoloading becomes supported by PHP, the Moto name-to-file resolution algorithm can support multiple functions per file:</p>\n<pre><code class=\"language-php\">// Foo_Bar\\Baz =&gt; /vendor/foo-bar/baz/src/dib.php\nnamespace Foo_Bar\\Baz;\n\nfunction dib() {}\n\nfunction dib_zim() {}\n\nfunction dib_gir() {}\n\nfunction dib_irk() {}\n</code></pre>\n<p>I'm soliciting feedback on this approach, so please post your comments and concerns at Github as <a href=\"https://github.com/motophp/autoload/issues\">issues</a> and <a href=\"https://github.com/motophp/autoload/pulls\">pull requests</a>.</p>\n"
}
