Skip to content

Instantly share code, notes, and snippets.

@AmyStephen
Last active December 18, 2015 16:19
Show Gist options
  • Save AmyStephen/5810668 to your computer and use it in GitHub Desktop.
Save AmyStephen/5810668 to your computer and use it in GitHub Desktop.
There are two basic issues with PSR-X. https://github.com/php-fig/fig-standards/blob/master/proposed/autoloader.md Neither one turn out to be a real problem. The first issue is only a perception problem. The second, developers can work around outside of an autoloader, if required.
<?php
// Problem 1: Problem only of perception or a Programmer Error.
//
// PSR-X allows the appearance of multiple FQNS to be assigned to a single class file.
// People might be confused and incorrectly assume the following is true.
//
// /path/to/packages/foo-bar/
// src/
// Baz.php # Foo\Bar\Baz
// Qux/
// Quux.php # Foo\Bar\Quax\Quux <== this is fantasy
// # Corge\Grault\Quux <== this is real
//
// Quux.php appears to have two *possible* FQNS: but really only has Corge\Grault\Quux
$loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');
$loader->addNamespace('Corge\Grault', '/path/to/packages/foo-bar/src/Qux');
// The situation would cause no errors by itself -- only if a developer
// used the incorrect namespace in code would it present:
$class = '\Foo\Bar\Quax\Qux';
if (class_exists($class)) {
// should return false
} else {
// could return true;
}
// Will fatal error if the developer uses an incorrect FQNS - just like any other such erroneous use
$instance = new $class();
// Why do I call this a programmer error?
//
// Which of the following is the BEST way to determine what the FQNS really is for a class file?
// 1. Look at the Composer.json file?
// 2. Apply the namespace of a neighbor file which just so happens to share a containing folder?
// 3. Look at the first line at the top of the class file? <== Correct answer. (And correct for PSR-X)
//
// First, the rules do not create a problem. PSR-X does *not* create multiple FQNS per class file.
// The only way a problem would even show up would be if developers used the wrong FQNS in code.
//
// Nothing in PSR-X says the namespace of the folder defines the class file namespace.
// It CAN but it is NOT a rule. People assuming otherwise does not mean the standard is at fault.
//
// Further, in order for this problem to actually manifest, a developer would have to select the
// wrong value to use in their code as the FQNS. That means the developer did not check the
// namespace definition within the file.
//
// For whatever reason, this problem in perception seeems to have people most concerned.
//
// OPTION 1: DO IT LIKE WE ALWAYS DO IT. LOCK IT DOWN.
//
// Bear in mind, we know this isn't a real problem but are pursuing the approach of separating namespaces
// into different physical folders, for no reason other than the risk that someone might confused.
//
// That means, PSR-X would include rules like these:
// i. Each folder MUST have no more than one namespace prefix assigned to it.
// ii. The folder namespace prefix MUST propagate down into the subfolders and ultimately to the class file.
// iii. A namespace prefix can only be assigned to a folder, never directly to a file.
//
// As a result, the folder system in the example has to be redesigned to separate classes into folders by namespace.
// As a result the FQNS might have to change (as in this example).
//
// /path/to/packages/foo-bar/
// src/
// Baz/
// Baz.php # Foo\Bar\Bar\Baz
// Qux/
// Quux.php # Corge\Grault\Quux
//
// Quux.php now not only has one FQNS, but it also appears that way when looking at composer.json and folder contents
//
$loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');
$loader->addNamespace('Corge\Grault', '/path/to/packages/foo-bar/src/Qux');
//
// OPTION 2: BUSINESS AS USUAL WITH ROOM FOR INNOVATION
//
// Enable autoloaders to continue as they have but stop short of activating hard rules defined above that
// would implement unnecessary restrictions and make it more difficult to use PSR-X for resource loading.
//
// Add a rule like this:
// i. Each class file must have a canonical namespace associated with an absolute path that can be used by
// the autoloader to identify and include the file.
//
// This rule would ALLOW autolaoders to use the Solution 1, points i, ii, and iii, without requiring it.
// This rule would not couple the logical namespace to a physical folder structure, thus retaining the flexibility.
// Features like resource loading and tagging could still be added without BC issues for class loading.
// The code examples for both are exactly the same. The only difference is Solution 2 deals with the *perceived problem*
// in a way that does not restrict PSR-X flexibility.
//
// Solution 3: EDUCATION
//
// As PSR-X rolls out, educate people on how it will be different than PSR-0.
// Don't change PSR-X because it is not broken.
//
<?php
// Problem 2:
//
// Ironically, the second is actually a problem in that currently, it is not possible to use
// a PSR-X autoloader in a predicatable way to override files
//
// For whatever reason, this problem doesn't seem to bother people as much. Most are willing to
// pass it off to the autoloader as an implementation issue and not add a rule to prevent failure.
//
// /path/to/packages/foo-bar/
// override/
// Baz.php # Foo\Bar\Baz
// src/
// Baz.php # Foo\Bar\Baz
//
// PSR-X allows a developer to define the location of an override file
// PSR-X does NOT define a rule that requires the autoloader use it.
$loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');
$loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/override');
// The error COULD manifest if the autoloader elected to use the first file defined, not the second.
// However, the problem MIGHT NOT manifest, if the autoloader selected the override file.
//
// How to fix it?
//
// Option 1: Add a rule like this:
// i. Autoloaders with addNamespaces methods MUST provide an append option which allows a developer to
// position the namespace before namespaces already defined.
//
// Option 2: Do nothing.
// Developers can still work around this by adding an spl_autoload of their own for overrides and
// registering with the prepend feature. ANYTHING they define will then be first.
//
public function registerMyOwnAutoloader()
{
spl_autoload_register(array($this, 'loadClass'), true);
}
// And then use THEIR loader to override the core namespace
$loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/override');
// Regardless - this problem can be solved without a rule change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment