[wp-trac] [WordPress Trac] #21300: Implement autoloader compatible with PSR-0 / PSR-4 for plugins and themes

WordPress Trac noreply at wordpress.org
Wed Feb 12 02:36:01 UTC 2014


#21300: Implement autoloader compatible with PSR-0 / PSR-4 for plugins and themes
-----------------------------+------------------------------
 Reporter:  dave1010         |       Owner:
     Type:  feature request  |      Status:  new
 Priority:  normal           |   Milestone:  Awaiting Review
Component:  Bootstrap/Load   |     Version:
 Severity:  normal           |  Resolution:
 Keywords:                   |     Focuses:
-----------------------------+------------------------------

Comment (by MikeSchinkel):

 -1 on a PSR-0 or PSR-4 compatible auto-loader and on the use of Composer
 for plugins and themes.

 Those three are all PHP ''"best practices,"'' but I think most of us know
 that WordPress has it's own best practices that are at times conflicting
 with PHP best practices, and for good reason.

 PHP best practices for configuration management typically target those who
 are setting up development, testing, staging and production environments
 where PHP will be deployed and used and where code is deployed by either
 developers or system administrator.  All of those features work very well
 for that use-case, but WordPress has a different primary use-case.

 The WordPress use-case is to have the core code deployed by site builders,
 many of whom cannot write PHP code, or even by automated app installers
 like Fantasico. And then plugin and theme code is often deployed by end-
 users. The WordPress use-case uses well-known directory structures, i.e.
 `/wp-content/themes`, `/wp-content/plugins` where self-contained and all-
 inclusive ''"packages"'' are installed; this minimizes users needing to be
 involved on a technical level.

 Across plugins and themes there is potentially a large number of classes
 to autoload, but those classes do not follow the PSR-0/4 autoloader
 standard because there is no single top-level directory to load from, nor
 are there really vendor names. You can ignore the lack of common root and
 simulate vendor name with plugin name but then the class files either need
 to be in the root of the theme/plugin or they need to be stored in
 subdirectories that would be considered namespaces themselves. All-in-all
 this feels like a round peg in a square hole.

 Another solution would be for WordPress to implement an autoloader and
 then every plugin and theme  could opt-in to the autoloader, thus creating
 many top-level autoloader roots. But that seems silly because it might
 follow the letter of the PSR autoloaders but not the spirit, and we could
 end up with deeper subdirectory structures this way too.

 What I would propose instead of a PSR-0/4 auto-loader is a WordPress
 autoloader that is much simpler, one that has only the following method:

 {{{
 register_autoload_path( $path_from_wp_content, $class_prefix )
 }}}

 It might look like this in use:

 {{{
 register_autoload_path( 'plugins/my-plugin', 'My_Plugin_' )
 }}}

 Then any plugin can register it's class paths in a
 `'register_autoload_paths'` hook that I'd proposed to be called by
 WordPress just before `'init`` and WordPress can collect all those files
 into an array and run a very simple autoloader when needed:

 {{{
 function _autoload( $class_name ) {
         if ( isset( $this->_autoload_classes[$class_name] ) ) {
                 require( $this->_autoload_classes[$class_name] );
         }
 }
 }}}

 And for those concerned the overhead of directory scans we could allow
 optional hardcoded autoloader registration like this:

 {{{
 register_autoload_path( 'plugins/my-plugin', array(
         'My_Plugin_Foo_Class' => 'class-foo.php',
         'My_Plugin_Bar_Class' => 'class-bar.php',
         'My_Plugin_Baz_Class' => 'class-baz.php',
 ));
 }}}

 FWIW I've implemented a library where you can see the autoloader
 [https://github.com/newclarity/ExoWP/blob/master/core/class-
 autoloader.php#L62 here] although it doesn't support the hardcoding I
 mention above.

 **HOWEVER, the idea of an autoloader is mostly moot anyways**, at least
 until we make some significant changes in WordPress and/or best practices
 for plugin and theme development all because of how WordPress plugins and
 themes bootstrap themselves.

 There are few non-trivial plugins or themes do not add actions or filters
 on the 'init' hook, and most developers I've seen using classes place
 these hooks in the a method of the class file. And placing hook
 initialization code outside of classes means separating the hook from the
 code it invokes making maintenance more difficult. And most of my systems
 I've worked on have over 50 classes and even with all those classes very
 few of them are without actions or filters that need to be hooked on page
 load. So if you autoload those classes you don't end up setting the
 actions and filters the code requires.

 So yes we can get an autoloader, even a PSR-0/4 autoloader, but it would
 be a Pyrrhic victory. At least until WordPress adds an alternate approach
 to registering post types, taxonomies, and hooks I can't see an autoloader
 providing any real, practical benefit for WordPress.

 BTW, for the library I mention above the approach I'm using is a different
 run-mode for development vs. deployment; in the former all classes are
 loaded and then the array of classes and class paths is serialized to a
 file that gets loaded when deployed for production. This works well for
 building sites where version control is used between development source
 and production deployment but would not really work well for the normative
 WordPress use-case of end-users adding plugins and themes on live sites.

 Replying to [comment:5 griffinjt]:
 > I've implemented a PSR-0 compliant autoloader in
 [http://wordpress.org/extend/plugins/soliloquy-lite/ Soliloquy] and so far
 there have been no issues (over 10k+ downloads total for free and paid)
 that have been reported.

 Hmm. Didn't want to pick on your work here, but since you presented it as
 an example of an autoloader done right I figured you'd be okay to open it
 for discussion.

 I just downloaded Soliliquy Lite and compared to [https://github.com/php-
 fig/fig-standards/blob/master/accepted/PSR-0.md PSR-0] and unless I'm
 missing something Soliliquy Lite is not PSR-0 compatible because it
 doesn't use [http://www.php.net/manual/en/language.namespaces.php PHP
 namespaces], and that's appears to be a requirement in PSR-0 ''(as well as
 in PSR-4):''

 > ''- A fully-qualified namespace and class must have the following
 structure:
 > ''`\<Vendor Name>\(<Namespace>\)*<Class Name>`
 > ''- Each namespace must have a top-level namespace ("Vendor Name").

 ''As an aside, you could add Namespaces but until core adds Namespaces and
 sets a precent for usage in WordPress I'm going to stick with "poor-man's
 namespacing" (i.e. prefixes.)''

 More importantly, it appears  you are loading hooks in the constructor of
 most of your classes, and then in the main `'init'` hook you are creating
 instances of all those classes ''(in the admin)'' or just 3 of the 9
 outside the admin. And outside the admin don't appear to be creating new
 instances of the others. So of the two main code paths admin and front end
 you are always instantiating the same classes, per code path.

 And in your autoloader you are using a `file_exists()` call before your
 `require()` call so your plugin is doing double work for each file you are
 loading. If you only needed to load a small subset of classes autoloading
 is definitely better, but if you are going to autoload every class every
 time anyway I'd argue you'd be better off getting rid of the autoloader
 and just doing direct `require()`s for the classes you plan to instantiate
 within `init`.

 So I recommend we close this ticket as **''maybelater.''**

--
Ticket URL: <https://core.trac.wordpress.org/ticket/21300#comment:12>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list