[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