Skip to content
This repository has been archived by the owner on Apr 22, 2020. It is now read-only.

Latest commit

 

History

History
214 lines (168 loc) · 6.59 KB

issue-36335.md

File metadata and controls

214 lines (168 loc) · 6.59 KB

WP core autoload proposal

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 missing most with WordPress. 1

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 leads to trouble right now 2. 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 a given class. The class is provided by its full qualified name. This leads to this interface signature:

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:

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 provided by the core should depend on a file loader. The file loader receives a file name and loads it, if it is present.

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:

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:

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

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.

Usage example from a plugin (not 5.2 compatible)

add_action( 'wp_autoload', function( $autoloader ) {

	$autoloader->addRule(
		new WP_Autoload_Psr4Rule(
			'MyPlugin\\'
			__DIR__ . '/src'
		)
	);
} );

Things to discuss

  • The proposal uses sensible interface names 3 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 that Psr4 is very wide-spread and encourage developers to use case sensitive this is a problem 4. 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 :)