Jul 7, 2014

Drupal 8 requires PHP 5.4 or higher, and PHP traits


Having to migrate from an older version of PHP could be an issue for some hosting providers or for your local dev environments.

PHP 5.4 included major additions to the language. There's a long, amazing discussion about this in the second source article below, Require PHP 5.4, with almost two hundred comments by Drupal core maintainers and others!

Many of those comments dealt with the availability of traits. I did not know anything about that language feature before this. It's a bit of a controversial feature for which there is no shortage of opinions about how to use it and how not to use it.

For myself, as a simple learning exercise and in order to eliminate a small amount of duplication, I decided to refactor the code I had previously written to look up paths, as described in this older post:  http://optimizely-to-drupal-8.blogspot.com/2014/06/function-drupallookuppath-has-been.html

I had added two private wrapper methods to a class. I now extracted those methods into a new trait. Autoloading seems to work the same as for classes, i.e. define the trait in its own file, name the file the same as the trait, and place the file into the directory structure where the autoloader will find it.

The result was (with code comments removed),

File:  optimizely/src/LookupPath.php

namespace Drupal\optimizely; 

trait LookupPath  {

  function lookupPathAlias($path) {
    $alias = 

        \Drupal::service('path.alias_manager')
            ->getPathAlias($path);
    return (strcmp($alias, $path) == 0) ? FALSE : $alias;
  }
 

  function lookupSystemPath($alias) {
    $path = 

        \Drupal::service('path.alias_manager')
            ->getSystemPath($alias);
    return (strcmp($path, $alias) == 0) ? FALSE : $path;
  }

}


Syntactically, the definition of a trait looks a lot like a class.

Then, for example, in any class that needs these methods, use the trait, then call the methods as though they are defined in the class itself.

class ProjectListForm extends FormBase {

  use LookupPath;


  // . . .
      $path_alias = $this->lookupPathAlias($front_path);
  // . . .

}

This is a very nice way to reuse snippets of code and adhere to the DRY principle.

(At the moment, I am running Drupal 8 on Windows using PHP 5.4.15.)

Sources:

System requirements
https://drupal.org/requirements

Require PHP 5.4
https://drupal.org/node/1498574

Traits
http://php.net/manual/en/language.oop5.traits.php

PHP: Traits vs. Interfaces
https://stackoverflow.com/questions/9205083/php-traits-vs-interfaces

4 comments:

  1. For what it's worth, use of tertiaries is discourage in D7 coding standards. Perhaps this has changed in D8?

    ReplyDelete
    Replies
    1. So far, I haven't seen anything about the use of the ternary operator, including in the coding standards that I've happened across.

      I always strive for clarity first, then brevity. So I do use the ternary op as long as the resulting code is clear and easy to understand. That almost always means that the code is also concise.

      Otherwise, I prefer use of an "if-else" statement and try to avoid being too clever.

      Delete
  2. Do you know of any guidelines as to when to use traits?

    ReplyDelete
    Replies
    1. There are some good answers in this StackOverflow item: https://stackoverflow.com/questions/9205083/php-traits-vs-interfaces

      I think the lengthy comment by rdlowery is especially worth reading. It's near the top of the page.

      My use of a trait in this post is just an example of code reuse of two small methods. But now that I've looked at it again, defining a class instead of a trait, and declaring a property of that class within the client classes that need the functionality might be a better way to go.

      Delete