[wp-trac] [WordPress Trac] #36335: Next generation: core autoloader proposal
WordPress Trac
noreply at wordpress.org
Fri Mar 25 19:21:44 UTC 2016
#36335: Next generation: core autoloader proposal
-----------------------------+-----------------------------
Reporter: dnaber-de | Owner:
Type: feature request | Status: new
Priority: normal | Milestone: Awaiting Review
Component: General | Version:
Severity: normal | Keywords:
Focuses: |
-----------------------------+-----------------------------
Hello WordPress community. With this ticket I would like to get the debate
of the last days about how to attract WordPress to developers (or the
other way around?) to a concrete discussion on how a class autoloader
could look like in WordPress core.
So when we start to think about some major improvements like in
https://core.trac.wordpress.org/ticket/36292, whe should also take some
time and talking about autoloading.
== Abstract ==
A class autoloader is a basic tool to separate code writing form code
organization. It takes care about providing class declaration at the point
they are needed. The fact that WordPress lacks of a core autoloader was
one point mentioned in the debate on what developers
[https://www.alainschlesser.com/attracting-developers-wordpress/ missing
most with WordPress].
== Why we need an autloader ==
Plugin authors using autoloaders these days. They even use composer for
dependency management and ship their plugins with this dependencies. This
practice [https://github.com/composer/composer/issues/3852 leads to
trouble right now]. I'm convinced that in a long-range plan we even have
to talk about how to deal with proper dependency management to overcome
collisions. Having an autoloader in core is a precondition for this.
== How an implementation could look like ==
The following proposal follows a concept of separating the file locating
and file loading process to avoid a violation of the single responsibility
principle and to gain flexibility. All classes and interfaces are prefixed
with `WP_Autoload_` to apply a pseudo namespace.
The main instance of this concept is the interface `WP_Autolaod_Rule`. A
autoload rule is against the client responsible for locating and loading a
given class. The class is provided by its full qualified name. This leads
to this interface signature:
{{{#!php
<?php
interface WP_Autoload_Rule {
/**
* @param string $class (A full qualified class name)
*
* @return bool
*/
public function load_class( $class );
}
}}}
Implementations could be `WP_Autoload_Psr4Rule`, `WP_Autoload_Psr0Rule` or
`WP_Autoload_ClassMapRule` or what ever plugin and theme authors want to
implement for their requirements. Here's a quick example:
{{{#!php
<?php
class WP_Autoload_Psr4Rule implements WP_Autoload_Rule {
/**
* @var string
*/
private $base_namespace;
/**
* @var string
*/
private $base_directory;
/**
* @var WP_Autoload_FileLoader
*/
private $file_loader;
/**
* @param $base_namespace
* @param $base_directory
*/
public function __construct( $base_namespace, $base_directory,
$file_loader = NULL ) {
$this->base_directory = (string) $base_directory;
$this->base_namespace = (string) $base_namespace;
$this->file_loader = $file_loader && is_a( $file_loader,
'WP_Autoload_Fileloader' )
? $file_loader
: new WP_Autoload_IsReadableFileLoader;
}
/**
* @param string $class (A full qualified class name)
*
* @return bool
*/
public function load_class( $class ) {
// performing the psr4 mapping here to get a $file
$file = '/whatever';
return $this->file_loader->load_file( $file );
}
}
}}}
Autoloading rules should depend on a file loader. The file loader receives
a file name and loads it, if it is present.
{{{#!php
<?php
interface WP_Autoload_FileLoader {
/**
* @param string $file
*
* @return bool
*/
public function load_file( $file );
}
}}}
A very simple implementation can just ask for `is_readable()`. Looking on
performance, another implementation could `glob()`-ing a given directory
once to read in all PHP-files and matching the given file against this
list. Even persistent caches are thinkable.
Last but not least `WP_Autoload_Autoload` acts as a repository for all
possible rules:
{{{#!php
<?php
interface WP_Autoload_Autoload {
/**
* @param WP_Autoload_Rule $autoload_rule
*
* @return void
*/
public function add_rule( $autoload_rule );
}
}}}
The main implementation should be `WP_Autoload_AutoloadSpl` which connects
to PHP standard library autoload:
{{{#!php
<?php
class WP_Autoload_SplAutoload implements WP_Autoload_Autoload {
/**
* @var WP_Autoload_Rule[]
*/
private $rules = array();
/**
* @param WP_Autoload_Rule $autoload_rule
*
* @return void
*/
public function add_rule( $autoload_rule ) {
if ( ! in_array( $autoload_rule, $this->rules, TRUE ) )
$this->rules[] = $autoload_rule;
}
/**
* @param string $fqcn (full qualified class name)
*/
public function load_class( $fqcn ) {
foreach ( $this->rules as $rule ) {
if ( $rule->load_class( $fqcn ) )
break;
}
}
}
}}}
== Instantiate and propagate the autoloader ==
{{{#!php
<?php
function wp_setup_autoloader() {
$autoloader = new WP_Autoload_SplAutoload;
spl_autoload_register( array( $autoloader, 'load_class' ) );
/**
* Use the WordPress core autoloader to
* bootstrap your plugin and theme
*
* @param WP_Autoload_Autoload $autoloader
*/
do_action( 'wp_autoload', $autoloader );
}
}}}
`wp_setup_autoloader()` should then be called early in the WP loading
process.
{{{#!php
<?php
add_action( 'wp_autoload', function( $autoloader ) {
$autoloader->addRule(
new WP_Autoload_Psr4Rule(
'MyPlugin\\'
__DIR__ . '/src'
)
);
} );
}}}
== Things to discuss ==
* The proposal uses [http://verraes.net/2013/09/sensible-interfaces/
sensible interface names] which I prefer over naming interfaces like
`WhateverInterfaces`. As WordPress does not provide interfaces right now,
this is just a suggestion.
* PHP class identifiers are case insensitive. That means `new MySql` and
`new MySQL` will both work, if a class `mysql` is declared. The autoloader
should respect this. Now, Psr4 is very wide-spread and encourage
developers to use case sensitive autoloaders and [https://r.je/php-
autoloaders-should-not-be-case-sensitive.html this is a problem]. How can
we deal with this in a performant way?
* How should the WordPress core files be organized to work with the
autoloader? Is it realistic to rearrange them, if not how could a
corresponding `WP_Autoload_Rule` look like?
* What about compatibility with PHP 5.2.? The proposal uses
`spl_autoload_register`. But before PHP 5.3.0 it is theoretically possible
to deactivate the spl extension. In this case another implementation of
`WP_Autolad_Autoload` would be necessary and maybe some adaptions to the
other interfaces. But is this really the intention?
== Finally ==
Thanks for reading. Feel free to add your concerns, your opinions or even
if I'm on a completely wrong train. In fact
I'm really interested in critic. To be clear, I don't want to push this
proposal but I would like to see a proper
autoloader in core some day :)
--
Ticket URL: <https://core.trac.wordpress.org/ticket/36335>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list