Accueil / A Look at PHP's Continuing Evolution

A Look at PHP's Continuing Evolution

Guest post by Larry GarfieldLarry Garfield is a Senior Architect at Palantir.net, a web consultancy based in Chicago. When not developing sites for clients, he can also be found leading the Drupal 8 Web Services Initiative, evangelizing good coding practices, working to bring the PHP world closer together through the PHP Framework Interoperability Group, or providing training either for clients or the Drupal community. Occasionally he remembers to sleep.

PHP is not a young language. As of 2013, it's 18 years old; that's old enough to vote. Many upstart languages have appeared over the years to try and unseat PHP as the "lingua franca" of web applications but it still commands over 80% of the web market. One reason for PHP's popularity is no doubt the ease with which new developers can get started with it, but just as important is the fact that PHP has been evolving for all those 18 years.

Many PHP detractors had cited the language's sometimes inconsistent APIs or its procedural nature as a reason that PHP was just a "toy language." That charge is true... or rather, it was during the 1990s. What is true now is that PHP is an eclectic language that isn't bound to a single world-view or architecture – and this is one of its strengths. Procedural, Object-oriented, and Functional programming styles all have their pros and cons. PHP lets you pick and choose what to use rather than forcing everything and everyone into a single mindset.

Recent versions of PHP have expanded its capabilities, too, to keep up with evolving markets and technical requirements. Let's have a look at three of the more recent additions to PHP's arsenal that help it remain the world's leading server-side language.

Anonymous functions and closures

PHP 5.3 introduced anonymous functions to PHP for the first time. The syntax is quite simple, too:

<?php
$c
= 5;
$max_cap = function ($a, $b) use ($c) {
 
$max = max($a, $b);
  return
min($max, $c);
};
$max_cap(3, 6);
?>

This trivial function lets us create a routine that returns the maximum of 2 values, but with an overall limit. We can now call it from anywhere we pass $max_cap to. While this example may not be very useful per se, specifying one-off logic routines without a dedicated function can be extremely useful. Consider array_map(), which applies a function to every element of an array:

<?php
$factor
= 3
$triple
= array_map(function($elm) use ($factor) {
  return
$elm * $factor;
},
$array);
?>

$triple now contains all the elements of $array, multiplied by 3. There are far far more powerful opportunities with anonymous functions that can and have justified their own articles, so we'll leave that for now and just mention object binding.

As of PHP 5.4, anonymous functions can also be "bound" to an object. That is, $this within a closure can refer to an object we specify, like so:

<?php
class  Foo {
  private
$count = 0;
}
$func = function() {
  return ++
$this->count;
};
$foo = new Foo();
// second param specifies scope so it can access private vars.
$bound = $func->bindTo($foo, $foo);
print
$bound(); // prints 1
print $bound(); // prints 2
?>

For more on anonymous functions, see the PHP manual entries on anonymous functions and class closure.

Traits

PHP 5.4 also added a new feature for the OO crowd: Traits. Traits are, essentially, "compiler-assisted copy and paste" – or, sane multiple inheritance. They let you define methods that can be added to a class at code time without inheritance.

<?php
trait World {
  protected function
scope() {
    return
'World';
  }
}

class
Hello {
  use
World;
  public function
hello() {
    return
"Hello " . $this->scope();
  }
}
?>

To be sure, traits are not and should not be used as an alternative for object composition. Their main use is to minimize boilerplate code needed to fulfill an interface. Proper use of traits can greatly reduce boilerplate code while still allowing for clean separation and interface-centric development.

For more on traits, see the PHP manual entry on traits.

Generators

PHP 5.5 added a feature called generators. Generators are in some sense a greatly abbreviated syntax for iterators, but being so simple makes them considerably more powerful. Essentially, a generator is just a function that returns-and-pauses rather than returns-and-ends, and what is returned is not a value but an iterator. The canonical (if trivial) example is iterating an "array" with 10 million items, which normally would cause memory issues:

<?php
function xrange($start, $limit, $step = 1) {
  for (
$i = $start; $i <= $limit; $i += $step) {
    yield
$i;
  }
}
foreach (
xrange(1, 10000000, 5) as $i) {
  print
$i . PHP_EOL;
}
?>

PHP notices the yield keyword, so when xrange() is called, an iterator object is returned. Every time foreach() asks that object for the next value, xrange() runs until it hits a yield and returns that value; the next time it's called, it continues from right after that yield statement until it hits another yield or exits. The above code will print every 5th integer from 1 to 10 million, and use no more than a kilobyte of memory in the process.

You can also pass data into a generator via yield. For a less trivial example, let's copy data from one file to another, stripping out all comment lines along the way.

<?php
function no_comments($filename) {
 
$handle = fopen($filename, 'r');
  while ((
$buffer = fgets($handle, 4096)) !== false) {
    if (
strpos($buffer, '//') !== 0) {
      yield
$buffer;
    }
  }
 
fclose($handle);
}

function
stripped_file($file) {
 
$f = fopen($file, 'a');
  while (
true) {
   
$line = yield;
    if (
is_null($line)) {
      break;
    }
   
fwrite($f, $line);
  }
 
fclose($f);
}
$out = stripped_file('output.php');

foreach (
no_comments('input.php') as $line) {
 
$out->send($line);
}
$out->send(null);
?>

A tiny bit of setup and the resulting code at the end couldn't possibly be easier! And the memory usage is trivial.

You can read all about this, too, in the PHP manual entry on generators!

Conclusion

PHP has lasted as long as it has, and gained the marketshare it has because it is flexible. That flexibility is increasing with every version. We've only barely scratched the surface of modern PHP here. Since PHP 5.2, every release of the language has offered new features and functionality to give developers more power and more options than ever before.

That 80% marketshare is not going anywhere anytime soon.

Commentaires

Posted on by DDevine (non vérifié).

Good post, well written.
I don't use PHP any-more but these changes will make me happy if I ever do use it again for anything mildly serious.

Posted on by PK (non vérifié).

You write "This trivial function lets us create a routine that returns the maximum of 2 values, but with an overall limit."

But it is not really capped at all, there is no "overall limit". The function will only return the value of $c, when $c is higher than max($a, $b).

Also, with PHP 5.4.15 I tested with, the definition of the anonymous function needs to end with a semicolon.

Posted on by Rujero (non vérifié).

If I am not mistaken you are missing a ; and the second max should be a min...

<?php
$c = 5;
$max_cap = function ($a, $b) use ($c) {
$max = max($a, $b);
return min($max, $c);
};
$max_cap(3, 6);
?>

Posted on by Larry Garfield.

PK and Rujero: D'Oh! That's what I get for writing code without writing unit tests for it. :-) Fixed. Thanks.

Posted on by Dave Ingram.

Great article, Larry, thanks!

Off the top of your head, are there some areas of Drupal that will see big improvements by adopting some of these new language features?

(Or phrased differently, which subsystems will you be rewriting in D9?) :)

Posted on by Larry Garfield.

We're already using anonymous functions in several places in D8; not as many as we could have, though, since anonymous functions cannot be serialized and Drupal over-serializes objects far too much at times. We could likely leverage them more than we are if we could decouple the code further.

Traits are the biggie. There's a ton of boilerplate code and unnecessary parent classes, particularly in the plugins system, that we could eliminate in favor of traits. Most of the people working on Plugins, controllers, forms, and the like have said "my kingdom for traits" at least four times. :-)

Generators.. I'm not sure. At least as the system is structured now there's no place that they'd be a super-simplification; more there are places where stylistically it could be nice to leverage them. (Especially consider combining anonymous functions and generators for lazy-running code.)

As for Drupal 9, come see my Core Conversation at DrupalCon Prague. ;-)

Posted on by Alice Smith.

Love it

Posted on by Jeremy Epstein (non vérifié).

As others have commented on articles similar to this one elsewhere: this demonstrates not how PHP is "evolving", but simply how it is catching up to where other languages were 10+ years ago (particularly Python), by way of blatantly copying their features (and attempting to implement them just as elegantly, but failing).

Although I know PHP better than, and use it more than, any other language (and although I'm happy that these features have been added), I recognise its flaws. It's not an evolving language. It's a collection of patch-work and band-aids. This is just the latest and greatest of the band-aids. Let's get real here, folks.

Posted on by Noah (non vérifié).

That is amazing that PHP is 18 years old now.

Posted on by Dalin (non vérifié).

"the language's sometimes inconsistent APIs"

This part hasn't been fixed. Does that function name use underscores, or does it just mash it all together? In what order are its arguments: haystack-needle, or needle-haystack?

In my mind these are more important (and easier) things to clean up rather than adding new OOP features. These sorts of issues illustrate why PHP is not as elegant as something like jQuery.

Ajouter un commentaire

Plain text

  • Aucune balise HTML autorisée.
  • Les adresses de pages web et de courriels sont transformées en liens automatiquement.
  • Les lignes et les paragraphes vont à la ligne automatiquement.

Filtered HTML

  • Use [acphone_sales], [acphone_sales_text], [acphone_support], [acphone_international], [acphone_devcloud], [acphone_extra1] and [acphone_extra2] as placeholders for Acquia phone numbers. Add class "acquia-phones-link" to wrapper element to make number a link.
  • Pour publier des morceaux de code, entourez-les avec les balises <code>...</code>. Pour du PHP, utilisez. <?php ... ?>, ce qui va colorier le code en fonction de sa syntaxe.
  • Les adresses de pages web et de courriels sont transformées en liens automatiquement.
  • Tags HTML autorisés : <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <h4> <h5> <h2> <img>
  • Les lignes et les paragraphes vont à la ligne automatiquement.
By submitting this form, you accept the Mollom privacy policy.