include, require, require_once, include_once. Do we need another file loader? No. But I wonder if another one might be useful if it is aimed towards how modern PHP code is used - import.
Also, let’s attack the function mess - please - haystack, needle / needle, haystack needs to go.
<?php
import( 'library or /path/to/php/class/file', 'namespace\path\to\import\into');
?>
There are critical differences from include and require
-
Import expects the whole file to be php code. I know this will play some Hell with IDE’s maybe, but it should make for faster parsing to be able to call a subroutine that doesn’t need to take html token switching into account. I could be wrong.
-
Import pulls in libraries or class files. It compiles but does not execute them - runtime executable code will be discarded by import, adding a measure of security since a class or function library must both be loaded and called to be executed, where include and require can be tricked into executing code by simply pointing them at a bogus file. To illustrate, consider this file
class May {
function moo {
echo 'moo';
}
}
echo 'bad code';
With my proposal, the old include statements wouldn’t execute anything in this poisoned file under PHP 7 because there are no <?php ?> markers. True, the hacker can put them there, but import will parse error if it sees them. And when import pulls the file in, it loads the class but ignores the code outside of it (though perhaps throwing a E_WARNING).
Import also allows for the following change to the function table in PHP. There will be 2 core namespaces, legacy and standard. Standard will be a clean slate, functions with consistent names and argument orders, but also very small - just the most frequently used functions. Most functions will be off in libraries. So if you’re working with MySQL your program would start with
import('mysql');
If for some crazy reason you need to use two database engines at the same time you’d have a problem, but here import saves you by letting you say what namespace the library goes into.
import ('mysql', 'MySQL');
import ('postgre', 'PostGre');
As to the legacy namespace, it would be imported by default to the root namespace by a new PHP.ini setting that would be true in 7 and false in 8 because of the BC breaking havoc turning it off causes. The standard library would only include those functions that don’t namespace collide with legacy when in legacy mode. In standard mode the standard library would load along with some of the more common libraries likely to have collisions, such as ‘String’ and ‘Array’
As for file requires, import can reassign their namespace or append it, depending on how the namespace was setup. If the most common method was used
namespace MyNameSpace;
Then import’s directive is an override. If its done like this
namespace MyFirstNameSpace {
}
namespace MySecondNameSpace {
}
Then these namespaces become children.
So what about the use statement? It works as it always has, so if you import something into a namespace it doesn’t belong in use statements elsewhere would fail. However, this allows for “monkey” typing to be done at the language level, not at the DI level - let me explain.
Right now the new operator creates a hard dependency, we can’t do anything about.
class A {
public function __construct() {
$this->property = new B();
}
}
And we’re stuck. If we need to trade out B for a specific version we have to change A’s code - a problem if A is from someone else’s library. But with import we don’t need to touch A. Here’s how…
import ('/filepath/to/B', 'Original');
import('/filepath/to/new/B');
The class file for new B knows about this dastardly plan.
class B extends Original\B {
}
But class A knows nothing about the fact it’s now dealing with a new B.
Now, is this a stroke of genius or a blast of stupidity? I don’t know.