PHP packages that stand alone and still work together
Modular PHP libraries that work without being tied to a framework; they became the 39-package InitPHP ecosystem and Framework3.
What it does today
A family of 39 PHP packages — Router, Database, Cache, Mailer, Socket and the rest — each usable standalone or together, all shipped through Composer/Packagist under MIT. Any PHP developer who wants the pieces without buying into a framework can install them today.
- Started
- January 2021 — August 2022
- Left Labs
Form
Technologies
This one became a product:
InitPHPA PHP package is either part of a framework or a tool that stands on its own. Once you want both at the same time, writing a shared core package is the first solution that comes to mind — and it is also the wrong one.
On its own, or as a family
What was tried: let parts like Router, Database, Cache, Mailer and Socket work meaningfully when installed alone, and still form a framework when combined with the other packages in the family. The parts were written separately and each one answered a question by itself.
Thirty-nine packages and the framework on top
Thirty-nine independent packages plus a minimalist MVC framework sitting on top of them (Framework3). The common ground is type safety and PHPUnit tests; distribution goes through Composer/Packagist under the MIT licence.
PSR instead of a shared core
“Both alone and together” collides at exactly one point: if packages have to know about each other, there is a dependency between them, and that dependency breaks standalone installation.
The first solution that came to mind was a shared core package — something like
initphp/core carrying the interfaces and common helpers. That road would have
brought two things at once: every package would gain one more dependency, and
since no library outside the family would know that core, the family would
close in on itself.
The ground chosen was the PHP-FIG standards. Logger implements PSR-3, Container implements PSR-11; packages know a shared interface contract rather than each other. What that buys: the InitPHP Container accepts the InitPHP Logger, but it also accepts Monolog, and the InitPHP Logger plugs into somebody else’s PSR-11 container. What resolved the contradiction was not a core of the family’s own but a contract that already existed outside it.
Thirty-nine packages instead of one library
The family’s second decision was about packaging. One initphp/initphp package
instead of thirty-nine repositories, thirty-nine release lines and thirty-nine
Packagist entries would have made maintenance markedly cheaper.
The cost would have been passed on to the user. A project that wants only a Router
would have to install the Socket server, the Mailer and the Queue as well; every
upgrade would carry the changes of ten packages it never uses. What the split
buys: composer require initphp/router brings only the Router, and you never
see the TCP/TLS/UDP/SSL surface of the Socket library.
So what keeps it maintainable is not shared code but shared discipline: the same level of type safety in every package, the same PHPUnit habit, the same PSR compliance. The family holds together because it was written to the same rules, not because it shares a dependency.
The road to the ecosystem
The collection stopped being a set of scattered packages and became a maintained open source ecosystem. Details in the portfolio.