Namespacing and class autoloaders are two important tools provided by PHP that WordPress developers should take advantage of more frequently. I wrote about why, and provided a brief introduction to both of these tools in my last article for Torque. This article offers an in-depth introduction to namespaces in PHP.
Namespaces are the better, more flexible version of using unique preferences in your class names. In addition they help structure your directories and allow you to take full advantage of autoloaders that follow the latest standards, including Composer’s autoloader.
This article assumes that you’re already familiar with the basics of object-oriented PHP. If you’re not, be sure to read my introduction to the topic. I also have more resources on learning object-oriented PHP on my blog.
I’m also assuming you are using at least PHP 5.3. If you’re still using PHP 5.2, you really should stop, as that version of PHP, which reached its end of life in January 2011, is slow and insecure. Keep in mind that if you are looking to apply this in a plugin or theme for public release, you will run into users who are using PHP 5.2 and using namespaces will create a fatal error for those users, who almost certainly will not know why.
Namespacing Your Class
I’m going to walk you through using namespacing. In these examples, let’s assume that the plugin is called Fun Machine.
Here is what a typical class looks like using normal WordPress class naming standards:
<?php class Fun_Machine_Shortcode { /** * Process the shortcode * * @param $atts * * @return string */ public static function the_shortcode( $atts ) { $atts = shortcode_atts( array( 'foo' => 'fighter', 'dave' => 'grohl' ), $atts, 'fun-machine' ); return self::shortcode_callback( $atts['foo'], $atts['dave'] ); } /** * Callback for shortcode * * @param string $foo * @param string $dave * * @return string */ public static function shortcode_callback( $foo, $dave ) { return $foo.$dave; } } add_shortcode( 'fun-machine', array( 'Fun_Machine_Shortcode', 'the_shortcode' ) );
The class gets named first for the plugin’s name and then for the purpose of the class. This makes sense because naming it just for its purpose, IE “shortcode,” is a major problem since two classes can’t have the same name or a fatal error will occur. What would happen if another plugin added a class called shortcode? There would be a fatal error and both plugin authors would be guilty of _doing_it_wrong().
This system gets cumbersome, especially if you like having small, single-purpose classes. Instead, we can put this class in the “fun_machine” namespace. Here’s the class, just the outline, skipping the content with a namespace:
<?php namespace fun_machine; class shortcode { //do the same stuff }
Now that we have a namespace, the way we used add_shortcode() to register the shortcode from the first example isn’t going to work. We have to use the namespace in it. Namespaces are separated by a forward slash. The shortcode registration would become:
add_shortcode( 'fun-machine', array( '\fun_machine\shortcode', 'the_shortcode' ) );
If we wanted to call the shortcode_callback method in another class, we would use:
\fun_machine\shortcode::callback( $foo, $dave );
While I have been starting with a forward slash, that is not always necessary. The starting forward slash puts us into the global namespace, so it is not needed when in the same namespace.
To illustrate the difference, let’s look at three small classes.
Note: each of these should really be in their own file, which is something I will address in my next article on autoloaders.
<?php namespace fun_machine; class add_shortcode { /** * Process the "fun" shortcode * * @param $atts * * @return string */ public static function fun( $atts ) { $atts = shortcode_atts( array( 'foo' => 'fighter', 'dave' => 'grohl' ), $atts, 'fun' ); return shortcode_callbacks::fun( $atts['foo'], $atts['dave'] ); } } ?> <?php namespace fun_machine; class shortcode_callbacks { /** * Callback for "fun" shortcode * * @param string $foo * @param string $dave * * @return string */ public static function fun( $foo, $dave ) { return \less_fun\teeth::do_something_to_foo( $foo ); } } ?> <?php namespace less_fun; class teeth { /** * Does two fairly opposite things * * @param string $foo * * @return string */ public static function do_something_to_foo( $foo ) { return strtolower( strtoupper( $foo ) ); } }
In the first class a method, add_shortcode(), from the second class is called, and it works the same way as it would without a namespace, as they are in the same namespace. In the second class, a method from the third class is called. Since they are in different namespaces, we had to use the fully qualified namespace: \less_fun\teeth::do_something_to_foo
Nesting Namespaces
So far we have only used single namespaces, but namespaces can be inside of each other. For example, we could have a “shortcodes” namespace under the main namespace “fun_machine.” Here is what the classes would like:
<?php namespace fun_machine\shortcode; class add_shortcode { /** * Process the "fun" shortcode * * @param $atts * * @return string */ public static function fun( $atts ) { $atts = shortcode_atts( array( 'foo' => 'fighter', 'dave' => 'grohl' ), $atts, 'fun' ); return shortcode_callbacks::fun( $atts['foo'], $atts['dave'] ); } } ?> <?php namespace fun_machine\shortcode; class shortcode_callbacks { /** * Callback for "fun" shortcode * * @param string $foo * @param string $dave * * @return string */ public static function fun( $foo, $dave ) { return \less_fun\teeth::do_something_to_foo( $foo ); } } ?>
Now to register the shortcode we would need to do this:
add_shortcode( 'fun-machine', array( '\fun_machine\shortcode\add_shortcode', 'fun' ) );
Nesting namespaces helps make it easier to show what a class does, based on its namespaces. It also helps group classes by purpose and dictates file structure in a logical and consistent manner, which we will discuss in the next article.
Aliasing Namespaces
Without the ability to alias namespaces in classes, however, we would have to write those long namespaces over and over again. Fortunately, aliasing allows us to use methods of a class in a different namespace using only the class name.
Aliasing is accomplished with a simple “use” statement between the namespace declaration and the beginning of the class. Here is the shortcode_callbacks class from the previous examples, modified to alias the \less_fun\teeth class.
<?php namespace fun_machine; use \less_fun\teeth; class shortcode_callbacks { /** * Callback for "fun" shortcode * * @param string $foo * @param string $dave * * @return string */ public static function fun( $foo, $dave ) { return teeth::do_something_to_foo( $foo ); } } ?>
As you can see, I added a use statement, and as result I was able to change the line “return \less_fun\teeth::do_something_to_foo( $foo );” to “return teeth::do_something_to_foo( $foo );.” As you can imagine, if that class gets used more than once, this can simplify things greatly.
Namespace All The Things!!!
That’s all you need to know in order to start using namespaces in your WordPress development projects. After applying just a few new concepts — all of which are made easier by using a good IDE like phpStorm — your code will be easier to follow and more organized.
Also, now that you understand namespaces, you are better prepared for using class autoloaders (which I will cover next time) and for creating and using Composer libraries.
8 Comments