The Problem: Interoperability. That's really it. Scenario Alice provides whatchamacallit A that depends on other whatchamacallit D to work. Bob provides whatchamacallit B that also depends on D. Charles is using A and B. D gets updated with a new incompatible API to its prior version. Alice publishes an update which includes a security fix. Bob retired. Charles, who can't program, can't update to Alice's latest code. His site eventually gets pwned.
That's the problem. Packages with dependencies are not interoperable at this time. They must be self contained. This is why WordPress doesn't support Composer at all. Drupal, Laravel et al bypass this problem by forcing all their whachamacallits to stay on the same version. This has limited their market penetration compared to WordPress because, despite being significantly superior codebases in all respects, they aren't user friendly to someone who doesn't code at all. The Solution (10,000 overview) Composer could be made to allow interoperable packages, but it will need support at the language level to do so. Specifically, it needs to know who wants what. It can then make decisions based on that information. Composer's primary link to the language is the autoload closure it provides. That closure currently takes one argument - the fully qualified name of the symbol to be loaded - currently almost always classes as for various reasons function autoloading isn't a thing. Can it not take a second argument to modify its behavior? The current behavior is to flat require the file if it is found in accordance to whichever schema is in use. Perhaps we don't want that anymore - perhaps we want to return the file path to use. This allows the engine to make decisions about how exactly to include the file, including the possibility of monkey typing it as can be done in userland, though when done in userland this effectively generates a new package. (5,000 ft. overview) Suppose we have a whatchamacallit that declares its namespace as a new root independent of / . If a file inclusion happens in this namespace, this namespace prepends everything in the included file. So if I do a file include in the \MyPlugin namespace and that file declares its namespace as Twig, it will become \MyPlugin\Twig. That works, but direct file include is no longer the PHP norm though. Autoloading is. So we need to tell the Autoloader that we want a file path returned - do NOT require the file yourself in your namespace. This could be as simple as a boolean flag of true sent to the autoloader. BUT it isn't - the autoloader (usually composer) needs to know the identity of this requestor because by configuration in the package json (the details of which are wildly out of scope) it might change which file path it returns. When the engine gets the path it does the include and the prepending business on the fly that Strauss and similar packages already do in userland. (2,500 ft overview) The above I think would more or less work, but it would lead to massive code duplication as Whatchamacallit A and B now have their own D's at \A\D and \B\D (assuming namespaces match whatchamacallit names). Here's what I think would prevent that: A asks the autoloader for D. The autoloader returns a file path and the engine mounts to \D B asks for D. The autoloader returns a different file path so the engine mounts to B\D and rewrites the D file with the new namespace the same way Stauss would have done. This works except for the problem of who had the older version, A or B? and what order are A and B going to be asking - cause depending on the application's architecture this order is not guaranteed. To solve this the autoloader can tell the engine it is safe to mount the file on root using an array return of [path, true] and mount on the whatchamacallit's namespace if [path, false]. So A asks for D. Autoloader returns [path, false]. Engine maps to \A\D and monkey types D as needed. B asks for D. Autoloader returns [path, true]. Engine maps to \D Non whatchamacallit code at namespace C asks for D. It will get the same version B is using and the autoloader shouldn't be queried unless C makes this ask before B. When C asks the autoloader gets (string RequestedSymbol, null) so it can either do the require itself or return a string, either will work (and it has to be this way for backwards compat). When B asks the autoloader gets ( Requested, 'B' ) and it should return [path, true] I hope the above is followable. It's more of a morning brainstorm than a spec.