Posts tagged with php7

PHP 7 at Tumblr

Another big boy on the web upgraded to PHP 7. If you're not yet on the train heading for PHP7-ville, best get your ticket soon, you won't regret it.

At Tumblr, we’re always looking for new ways to improve the performance of the site. This means things like adding caching to heavily used codepaths, testing out new CDN configurations, or upgrading underlying software. Recently, in a cross-team effort, we upgraded our full web server fleet from PHP 5 to PHP 7. The whole upgrade was a fun project with some very cool results, so we wanted to share it with you.

https://engineering.tumblr.com/post/152998126990/php-7-at-tumblr

Read more

Join 9,500+ smart developers

Every month I share what I learn from running Spatie, building Oh Dear, and maintaining 300+ open source packages. Practical takes on Laravel, PHP, and AI that you can actually use.

No spam. Unsubscribe anytime. You can also follow me on X.

Changes to the type system in PHP 7.1

PHP 7.1 is nearing completion. A few days ago Release Candidate 1 was released. One of the areas that got some love from the developers is the type system. Pascal Martin wrote a blogpost about those changes.

One of the most important changes PHP 7.0 brought us last year was about typing, with the introduction of scalar type-declarations for functions/methods parameters and their return value. PHP 7.1 adds to those type-declarations, with several points that were missing in the previous version of the language.

https://blog.pascal-martin.fr/post/php71-en-types.html

That new iterable pseudo-type will sure come in handy.

If you want to know what's changed regarding error handling, Pascal has got that covered as well.

Read more

The new Closure::fromCallable() in PHP 7.1

PHP 7.1 will have a neat function to create closures from callables. Joseph Silber explains the function and offers some good examples on his blog.

With PHP 5.5 going EOL earlier this week and the PHP 7.1 beta expected later this month, now sounds like a good time to look into a neat little feature coming in 7.1: easily converting any callable into a proper Closure using the new Closure::fromCallable() method.
  • A short refresher on closures in PHP
  • When you need to convert a callable to a Closure
  • Introducing Closure::fromCallable()
  • Creating a closure that wraps a private method

https://josephsilber.com/posts/2016/07/13/closure-from-callable-in-php-7-1

Read more

PHP 7 usage at 20% according to Packagist stats

Jordi Boggiano, the creator and maintainer of Composer and Packagist, released some fresh statistics on which PHP version composer users are running.

A few observations: 5.3 dropped to almost nothing which is great news! 5.4 is also down by almost 10% and is definitely on the way out. 5.5 is still big but less so, while 5.6 got a huge boost to become the main version. The big surprise is that we have 20% of PHP7 already! That is great news only six months after this major release came out.

20% sounds really great, but I suspect that this number is slightly optimistic. Many developers who are running PHP 7 in their dev environment use PHP 5.X in production.

Over on the package side only ±20% of all packages require PHP 5.5 or above and only 1% requires PHP 7. Jordi has this to say about that:

All in all, it seems like package requires are way behind actual version usage, so I would like to encourage everyone to be a bit more aggressive in bumping PHP requirements when tagging new major releases of their libs.

That's great advice. The bulk of the newly released Spatie packages require PHP 7. In my opinion you'd do our ecosystem a favour by picking PHP 7 as a minimum requirement when you are creating a new package.

Read Jordi's entire post on his blog for more details: https://seld.be/notes/php-versions-stats-2016-1-edition

Read more

Anonymous classes benchmarked

Mark Baker made some fascinating benchmarks on the performance of PHP 7's anonymous classes.

A week or so ago, I published an article entitled “In Search of an Anonymous Class Factory” about my efforts at writing a “factory” for PHP7’s new Anonymous Classes (extending a named concrete base class, and assigning Traits to it dynamically); and about how I subsequently discovered the expensive memory demands of my original factory code, and then rewrote it using a different and (hopefully) more memory-efficient approach.

Since then, I’ve run some tests for memory usage and timings to assess just how inefficient my first attempt at the factory code was, and whether the new version of the factory really was better than the original.

https://markbakeruk.net/2016/05/12/anonymous-class-factory-the-results-are-in/

Read more

Upcoming changes in PHP 7.1

Amo Chohan wrote a rundown of the big changes coming tot PHP 7.1

  • Catching multiple exception types
  • Curl HTTP/2 server push support
  • Support class constant visibility
  • Void return types
  • Generalize support of negative string offsets
  • Allow specifying keys in list() and square bracket syntax for array destructuring
  • Warn about invalid strings in arithmetic
  • Deprecate and remove mcrypt()
https://medium.com/@amo.chohan/upcoming-changes-in-php-7-1-76ebea53b820#.2udxw3qfe

Read more

Upgrading PHP 5.6 to 7.0 on a Forge provisioned server

If you've read some posts before on this blog, then you'll probably know that I'm a big fan of Forge. The service makes it very easy to set up and administer servers. At my company we've been using it since it launched.

We currently have 80 provisioned servers. Most of them are small droplets. We have a policy of running every site on it's own droplet. This approach has many benefits, but that's maybe something for a future post.

The bulk of our servers are on PHP 5.6. That's not too bad, but once you have some sites on PHP 7, the sites running on those servers feel a bit slow. It's amazing how fast you get used to the speed that PHP 7 offers. That's why I experimented a bit with upgrading the PHP version on a Forge provisioned server. My gut feeling was that upgrading the PHP version is less work that setting up a new server and moving a site to it.

To not mess up a live site I created a snapshot and used that to set up a server to toy around with. With a little bit of research I came up with these instructions to upgrade the PHP version.

sudo add-apt-repository ppa:ondrej/php

sudo apt-get update

sudo apt-get install php7.0

sudo apt-get install php7.0-fpm

Depending on your project you will need less or more php extensions, but these were the ones relevant for my site:

sudo apt-get install php7.0-gd

sudo apt-get install php7.0-mysql

sudo apt-get install php-memcached

sudo apt-get install php7.0-mcrypt

sudo apt-get install php-curl

sudo apt-get install php-imagick

Next, in the nginx configuration of the site I replaced unix:/var/run/php5-fpm.sock with unix:/var/run/php/php7.0-fpm.sock

The final adjustment I made was to make sure nginx would spawn the php processes under the forge. This will make sure that a php process can write to sites previously created by Forge:

// in the file /etc/php/7.0/fpm/pool.d/www.conf
...
user = forge
group = forge
...

After that I rebooted the server (maybe just restarting nginx is enough) and enjoyed browsing a site that was four times as fast. ?

If you decide to try this out for your server, be aware that what works for me doesn't necessarily work for you. Every site is a bit different. But I'm sure the instructions from this post will get you pretty far. Happy upgrading!

EDIT: Meanwhile DigitalOcean also published a guide on how to upgrade to PHP 7.

Read more

Converting PHP 7 code to equivalent PHP 5 code

In the JavaScript world converting modern code to an older syntax is quite common. In the PHP world you don't see that happen often. Symfony provides a few polyfills, but a full fledged conversion isn't available. At the meetup of our local PHP user group Jens Segers, Hannes Van de Vreken and I were toying around with the idea of converting PHP 7 code to equivalent PHP 5 code automatically.

Today our little hobby project called 7to5 was tagged 1.0.0. You can view the repo on GitHub.

What does it do?

The tool will convert PHP 7 to PHP 5 by:
  • removing scalar type hints
  • removing return type hints
  • removing the strict type declaration
  • replacing the spaceship operator by an equivalent PHP 5 code
  • replacing null coalesce statements by equivalent PHP 5 code
  • replacing group use declarations by equivalent PHP 5 code
  • replacing defined arrays by equivalent PHP 5 code
  • converting anonymous classes to regular classes

Because there are a lot of small things that cannot be detected and/or converted properly it is not guaranteed that the converted code will work. It's highly recommended to run your automated tests against the converted code to determine if it works.

Using the tool

7to5 can be installed globally by running:
composer install global spatie/7to5

Once that's done you can use php7to5 to convert a whole directory in one go:

php7to5 convert {$directoryWithPHP7Code} {$destinationWithPHP5Code}

Behind the curtains

Removing some of the features of PHP 7 like scalar type hints and return type hints seems quite easy. Replacing anonymous classes, spaceship operators and null coaleasance operators is al little harder.

Image how you would convert this:

class Test
{
    public function test()
    {
        $class = new class() {
            public function method(string $parameter = '') : string {
                return $parameter ?? 'no parameter set';
            }
        };
        
        $class->method();

        $anotherClass = new class() {
            public function anotherMethod(int $integer) : int {
                return $integer > 3;
            }
        };
    }
            
}

to this:

class AnonymousClass0
{
    public function method($parameter = '')
    {
        return isset($parameter) ? $parameter : 'no parameter set';
    }
}

class AnonymousClass1
{
    public function anotherMethod($integer)
    {
        return $integer < 3 ? -1 : ($integer == 3 ? 0 : 1);
    }
}

class Test
{
    public function test()
    {
        $class = new AnonymousClass0();
        $class->method();
        $anotherClass = new AnonymousClass1();
    }
}

After the meetup of our usergroup the idea lay dormant for a while, but at this year's PHPUKConference Hannes decided to just do it™. I was immediately pulled in. We ran over a few options. It quickly became apparent that using regex was out of the question. Using a state machine would become very unwieldy fast too. We settled on using the PHP parser tool created by Nikita Popov. This tool can convert PHP code to an abstract syntax tree. It's very similar to a domtree for html code. Here's an example (taken from the php parser docs). This code:

echo 'Hi', 'World';
hello\world('foo', 'bar' . 'baz');

will get converted to this tree:

[
    0: Stmt_Echo(
        exprs: [
            0: Scalar_String(
                value: Hi
            )
            1: Scalar_String(
                value: World
            )
        ]
    )
    1: Expr_FuncCall(
        name: Name(
            parts: [
                0: hello
                1: world
            ]
        )
        args: [
            0: Arg(
                value: Scalar_String(
                    value: foo
                )
                byRef: false
            )
            1: Arg(
                value: Expr_Concat(
                    left: Scalar_String(
                        value: bar
                    )
                    right: Scalar_String(
                        value: baz
                    )
                )
                byRef: false
            )
        ]
    )
]

Here's the code to create the abstract syntax tree.

//create a parser
$parser = (new PhpParser\ParserFactory())->create(PhpParser\ParserFactory::PREFER_PHP7);

//feed it PHP 7 code
$php7code = file_get_contents($pathToPhp7File);

//this variable now contains the entire syntax tree
$syntaxTree = $parser->parse($php7code);

Now that we have created the abstract syntax tree, let's manipulate it. The tree can be traversed by a Traverser. The manipulation can be done by one or more Visitors objects. Let's view some code that traverses the tree and converts it back to regular PHP code.

$traverser = new PhpParser\NodeTraverser();

$traverser->addVisitor(new NullCoalesceReplacer());

$manipulatedTree = $traverser->traverse($syntaxTree);

//convert the tree back to regular code
$code = (new \PhpParser\PrettyPrinter\Standard())->prettyPrintFile($manipulatedTree);

file_put_contents($pathToFileWithManipulatedPhpCode, $code);

The real magic happens in the NullCoalesceReplacer class. It will convert all usages of the null coalesce operator, which is exclusive to PHP 7, to equivalent PHP 5 code. This class is not a part of Nikita's package. Hannes and I created it together with all other visitors.

Before taking a look at the code of that class, we'll first examine how we would manually replace a null coalesce operator.

//PHP 7 code
$result = $input ?? 'fixed-value';

//equivalent PHP 5 code
$result = isset($input) ? $input : 'fixed-value';

Let's describe the needed conversion in plain English. We'll need to create a ternary statement. The left hand side of the '??' needs to put in an isset statement. The true branch of the ternary statement needs to use the left hand side of the '??'-operator, the false branch needs the right hand side.

Here's the code of the NullCoalesceReplacer-visitor.

namespace Spatie\Php7to5\NodeVisitors;

use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp\Coalesce;
use PhpParser\NodeVisitorAbstract;

class NullCoalesceReplacer extends NodeVisitorAbstract
{
    public function leaveNode(Node $node)
    {
        //don't do at thing if the given node is not a Coalesce operator we
        if (!$node instanceof Coalesce) {
            return;
        }

        //create an isset functional call with the left side of '??' as the first parameter
        $issetCall = new Node\Expr\FuncCall(new Node\Name('isset'), [$node->left]);

        //replace the entire node by a ternary statement
        return new Node\Expr\Ternary($issetCall, $node->left, $node->right);
    }
}

Let's review another visitor. This one will remove all scalar type hints:

namespace Spatie\Php7to5\NodeVisitors;

use PhpParser\Node;
use PhpParser\Node\Param;
use PhpParser\NodeVisitorAbstract;

class ScalarTypeHintsRemover extends NodeVisitorAbstract
{
    public function leaveNode(Node $node)
    {
        if (!$node instanceof Param) {
            return;
        }

        if ($this->isScalar($node->type)) {
            $node->type = null;
        }
    }

    /**
     * @param string|null $type
     *
     * @return bool
     */
    protected function isScalar($type)
    {
        return in_array($type, ['int', 'integer', 'float', 'string', 'bool', 'boolean']);
    }
}

Using an abstract syntax tree sure makes manipulating code fairly readable. There are quite a number of other visitors. You can take a look at them on GitHub.

In closing

Honestly, I don't think I will ever use this tool myself. I'd rather upgrade a server to PHP 7 that converting code to PHP 5. That being said, it was a fun project to work on. It has a certain coolness factor. I learned that manipulating code using PHP parser is not that hard. Maybe I can use that knowledge on another project someday.

Meanwhile a more featured rich project that converts PHP 7 code has popped up (so if you do want to convert some PHP 7 code take a look at that one too).

Read more

Typed arrays in PHP

Tim Bezhashvyly recently wrote an article in which he explains an interesting approach to make sure all items in array are of a certain type. It leverages variadic functions which were introduced in PHP 5.6

Consider this piece of code (borrowed from Tim's post):

function foo (Product ...$products )
{
/* ... */
}

In PHP 7 you can even using the scalar types, such as string and int, to make sure all elements are of that type.

Read Tim's full article here: https://thephp.cc/news/2016/02/typed-arrays-in-php

Read more

Using emoji in PHP original

by Freek Van der Herten – 1 minute read

Using plain PHP it's kinda hard to display emoji characters. In PHP 5 those characters could be generated by using json_encode. echo json_decode('"\uD83D\uDE00"'); //displays ? I bet no one can type this code by heart. In PHP 7 it's a little bit easier. The hot new version of PHP…

Read more

Why we are requiring PHP 7 for our new packages

The past few weeks we released several new packages: laravel-sluggable, laravel-robots-middleware, laravel-glide and pdf-to-text. These packages have in common that they all require PHP 7. Because there were several reactions and questions about this, I'd like to shed some light on that decision.

I expect that lots of developers will make the move to PHP 7 in the coming year. Sure there will always be legacy projects that'll never see an upgrade, but it makes no sense starting a greenfield project in PHP 5.X. The performance benefits are just too good. On the package side I expect that some widely used packages will make the jump as well. Jordi Boggiano has already announced that the next version of Monolog targets PHP 7. Also keep in mind that active support for PHP 5.x is coming to end this August (or at the latest December).

Not only developers will make a quick move to PHP 7. The speed benefit is quite interesting for hosting companies as well. A speedier PHP version means a machine can host more sites. There quite a few hosting companies that already made the jump and are offering PHP 7 support.

When we work on projects at Spatie we have to solve a lot of problems. When we solve a problem in way that the solution can be used in future projects, we create a package. So we create these packages primarily for our own future projects. We decided that from now on every greenfield project wil be a PHP 7 one. So it makes sense that our new packages would require PHP 7 as well. By doing so we can make use of the latest new features such as the scalar type hints, return types, anonymous classes and the null coalescing operator. At some point all our projects will leave PHP 5.6 behind. The earlier we won't have to deal with PHP 5.X code anymore the better.

I'm well aware that requiring PHP 7 will hurt the popularity of our packages in the short run. But popularity is not our main goal. People who are using the latest and greatest version of PHP can benefit from our work. And I hope others will be nudged a bit towards PHP 7 by our decision.

(EDIT: we won't change the requirements of our older packages. PHP 7 will only be required when we create a new major version.)

Read more

The Road to Monolog 2.0

One of the main questions when doing a major release is which minimum PHP version to support going forward. Last summer I decided I wanted to do a big jump from 5.3 and directly target PHP 7. It provides a lot of nice features as well as performance improvements, and as Monolog is one of the most installed packages on Packagist I wanted to help nudge everyone towards PHP 7.
http://seld.be/notes/the-road-to-monolog-2-0

Read more