Giustino Borzacchiello

A PHP time-lapse: tools and resources for Modern PHP


PHP has come a long way since its humble beginnings as a simple scripting language and Modern PHP has several peculiar traits (see what I did there?)

But with a simple Google search along with great material about how to write Modern PHP you will find a lot of outdated blog posts or resources that should be ignored.

In this post, I’ve tried to collect a few outstanding resources that have helped me become a better PHP developer.

But first, the time-lapse.

I still remember the first website I created using PHP. It was during high school: I was teaching myself Turbo Pascal and I was able to do simple sites in HTML.

Then I saw a friend of mine programming, and it wasn’t Turbo Pascal. I remember that all those dollar signs were a bit strange.

What’s that? It’s a new programming language, it’s called PHP. You can build dynamic websites with it. What do you mean with dynamic?

Without talking, he wrote something like this:

<a id="cb1-1" class="sourceLine" title="1"></a><span class="kw">echo</span> <span class="st">'<ul>'</span><span class="ot">;</span>
<a id="cb1-2" class="sourceLine" title="2"></a><span class="kw">for</span><span class="ot">(</span><span class="kw">$i</span>=<span class="dv">0</span><span class="ot">;</span> <span class="kw">$i</span><<span class="dv">1000</span><span class="ot">;</span> <span class="kw">$i</span>++<span class="ot">)</span>{
<a id="cb1-3" class="sourceLine" title="3"></a>    <span class="kw">echo</span> <span class="st">'<li>Item number '</span> . <span class="kw">$i</span> . <span class="st">'</li>'</span><span class="ot">;</span>
<a id="cb1-4" class="sourceLine" title="4"></a>}
<a id="cb1-5" class="sourceLine" title="5"></a><span class="kw">echo</span> <span class="st">'</ul>'</span><span class="ot">;</span>

And reloaded the page (he was using EasyPHP as a local server).

One thousand li element created on the fly. ONE THOUSAND. It would have taken me a bit of time to write that in static HTML. I wanted, better, I needed to learn how to do that!

I copied the EasyPHP installer on some random floppy disk, along with some PHP files to learn from. That evening I wrote my first Hello, World and a great looking website that featured header, sidebar, main content, and footer all split into separate files and fetched via include. I felt powerful!

Fast forward five years

I’m at university and I find a little part-time job as a web developer. I’m excited about all the things I’m going to learn. They told me I need to migrate an app from PHP4 to PHP5. Of course, I wasn’t prepared for this:

<a id="cb2-1" class="sourceLine" title="1"></a><span class="co">//UPDATE LAST ACTION</span>
<a id="cb2-2" class="sourceLine" title="2"></a><span class="kw">$DB</span>->Execute<span class="ot">(</span><span class="st">"UPDATE users SET last_action=NOW() WHERE id="</span>.<span class="kw">$_SESSION</span><span class="ot">[</span><span class="st">'fw_userid'</span><span class="ot">]</span> <span class="ot">);</span>
<a id="cb2-3" class="sourceLine" title="3"></a>
<a id="cb2-4" class="sourceLine" title="4"></a><span class="co">//CHECK FOR EXPIRED PASSWORD</span>
<a id="cb2-5" class="sourceLine" title="5"></a><span class="kw">if</span> <span class="ot">(</span><span class="kw">$CONF</span><span class="ot">[</span><span class="st">'days_cpw'</span><span class="ot">]</span> > <span class="dv">0</span><span class="ot">)</span>
<a id="cb2-6" class="sourceLine" title="6"></a>{
<a id="cb2-7" class="sourceLine" title="7"></a>    <span class="kw">list</span><span class="ot">(</span><span class="kw">$yy</span><span class="ot">,</span><span class="kw">$mm</span><span class="ot">,</span><span class="kw">$dd</span><span class="ot">)</span> = <span class="fu">explode</span><span class="ot">(</span><span class="st">"-"</span><span class="ot">,</span><span class="kw">$_SESSION</span><span class="ot">[</span><span class="st">'user'</span><span class="ot">][</span><span class="st">'last_pw_change'</span><span class="ot">]);</span>
<a id="cb2-8" class="sourceLine" title="8"></a>    <span class="kw">$olddata</span> = <span class="fu">mktime</span><span class="ot">(</span><span class="dv">2</span><span class="ot">,</span><span class="dv">0</span><span class="ot">,</span><span class="dv">0</span><span class="ot">,</span><span class="kw">$mm</span><span class="ot">,</span><span class="kw">$dd</span><span class="ot">,</span><span class="kw">$yy</span><span class="ot">);</span>
<a id="cb2-9" class="sourceLine" title="9"></a>    <span class="kw">$span</span> = <span class="fu">time</span><span class="ot">()</span> - <span class="kw">$olddata</span><span class="ot">;</span>
<a id="cb2-10" class="sourceLine" title="10"></a>    <span class="kw">$days_passed</span> = <span class="kw">$span</span> / <span class="ot">(</span><span class="dv">60</span>*<span class="dv">60</span>*<span class="dv">24</span><span class="ot">);</span>
<a id="cb2-11" class="sourceLine" title="11"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="kw">$days_passed</span> > <span class="kw">$CONF</span><span class="ot">[</span><span class="st">'days_cpw'</span><span class="ot">]</span> && !<span class="fu">strstr</span><span class="ot">(</span><span class="kw">$_SERVER</span><span class="ot">[</span><span class="kw">SCRIPT_NAME</span><span class="ot">],</span><span class="st">"mod_user"</span><span class="ot">)</span> && !<span class="fu">strstr</span><span class="ot">(</span><span class="kw">$_SERVER</span><span class="ot">[</span><span class="kw">SCRIPT_NAME</span><span class="ot">],</span><span class="st">"calendar_iframe"</span><span class="ot">)</span>  && !<span class="fu">strstr</span><span class="ot">(</span><span class="kw">$_SERVER</span><span class="ot">[</span><span class="kw">SCRIPT_NAME</span><span class="ot">],</span><span class="st">"cron_web_start"</span><span class="ot">)</span> <span class="ot">)</span>
<a id="cb2-12" class="sourceLine" title="12"></a>    {
<a id="cb2-13" class="sourceLine" title="13"></a>            <span class="fu">header</span><span class="ot">(</span><span class="st">"location: "</span>.<span class="kw">$CONF</span><span class="ot">[</span><span class="st">'url_base'</span><span class="ot">]</span>.<span class="kw">$CONF</span><span class="ot">[</span><span class="st">'dir_modules'</span><span class="ot">]</span>.<span class="st">'admin/pages/mod_user.php?id='</span>.<span class="kw">$_SESSION</span><span class="ot">[</span><span class="st">'fw_userid'</span><span class="ot">]</span>.<span class="st">'&action=cp'</span><span class="ot">);</span>
<a id="cb2-14" class="sourceLine" title="14"></a>    }
<a id="cb2-15" class="sourceLine" title="15"></a>}
<a id="cb2-16" class="sourceLine" title="16"></a>
<a id="cb2-17" class="sourceLine" title="17"></a><span class="co">//Template inizialization</span>
<a id="cb2-18" class="sourceLine" title="18"></a><span class="kw">require_once</span> <span class="ot">(</span><span class="st">"template.php"</span><span class="ot">);</span>
<a id="cb2-19" class="sourceLine" title="19"></a>
<a id="cb2-20" class="sourceLine" title="20"></a><span class="co">// Load Modules configuration in memory</span>
<a id="cb2-21" class="sourceLine" title="21"></a>load_modules_config<span class="ot">();</span>
<a id="cb2-22" class="sourceLine" title="22"></a>
<a id="cb2-23" class="sourceLine" title="23"></a><span class="co">//Include permission manager</span>
<a id="cb2-24" class="sourceLine" title="24"></a><span class="kw">require_once</span> <span class="ot">(</span><span class="st">"permission.php"</span><span class="ot">);</span>

Of course, PHP4 wasn’t the problem…It was a rough ride, but it was fun!

Fast forward fifteen years

I want to try out a new idea for a simple web app. I cd into a folder and create a PHP file.

Then php -S localhost:8000 -t public/ will spin off a dev server for me.

I need to read some CSV file: composer require league/csv is all I need to do to download a robust library for CSV handling.

Since I want to make sure that my application is robust, let’s install a testing framework: composer require --dev phpunit/phpunit ^8.

I don’t like to use require_once all over the place: luckily Composer provides a PSR-4 compliant autoloader for free.

Now let’s try to make an API for that: I can choose from multiple PSR-15 Server Request Handlers that digest PSR-7 HTTP messages and focus just on my business logic.

Tools & Resources {#tools-resources}

If you want to know more, here are several resources and tools that have helped me learn more about the language.

PHP: The Right Way {#php-the-right-way}

If you could choose just one resource to know more about Modern PHP, then PHP: The Right Way would be that one.

It’s less about the language and more about the ecosystem and the best practices that have emerged during the years.

An absolute must-read.

Dependency management via Composer {#dependency-management-via-composer}

Composer logo
Composer logo

I can say without exaggeration that Composer is one of the best things happened to PHP. I always found PEAR confusing to use, while Composer is immediate and ubiquitous.

Of course, a dependency manager without packages to manage is a bit useless so I need to mention also Packagist, a repository where (almost) all PHP libraries are uploaded and fetched by Composer.

I think that Composer played a big part in the recent switch from monolithic framework to composing of libraries that

Some great reads about this topic:

Modern PHP {#modern-php}

Modern PHP book cover
Modern PHP book cover

Even if this book by Josh Lockhart is a bit old, it does a great job at explaining “new” features introduced in PHP and other best practices. It’s a great complement to PHP: The Right Way.

Psysh {#psysh}

The one thing I missed from my times as a Python developer was the iPython REPL. After discovering Psysh, my nostalgia faded away.

It’s simply the best REPL for PHP, and its doc feature gives me the ability to check the PHPdoc without leaving the terminal every time.

The doc command for array_map

The doc command for array_map

Testing {#testing}

A list like this wouldn’t be complete without mentioning some testing-related resource. But it will be a really obvious one.

I still feel that the best place to start is the PHPUnit Manual as far as PHP is concerned.

Then, if you want to learn more about testing in general and TDD, these are my top recommendations:

Modernizing Legacy Applications In PHP {#modernizing-legacy-applications-in-php}

Modernizing Legacy applications with PHP book cover
Modernizing Legacy applications with PHP book cover

We’ve all been there. During the interview, you’re sold futuristic technology and once you’re at your new job, you’re faced with a big, leaking bull of mud. And you just want to run away.

Modernizing Legacy Applications In PHP by Paul M. Jones helps you step by step untangle that mess. Really well written!.

So these are my favorite resources about Modern PHP: did I miss something? What’s yours?