Contemporary PHP Coding

Some of the notes here are really old, and use old practices. This is a rundown of contemporary practices circa 2016. I'm a few years behind, so, it's more like 2013 practices, but, there are still tutorials being written that don't use these better techniques. Get with the times.

Don't set up Apache. Instead use "php -S localhost:8000" to start a local server from the shell. The docroot will be in the current directory, and error logs go to the screen. This is important because current versions of PHP don't send messages to the browser.

Use namespaces. Just get into the habit of adding "namespace JK;" or whatever to the top of your scripts. Namespacing makes it easier to combine code in the future, and relieves you of thinking of unique global class names. Oh yeah, you also need to use "use".

Use Composer. If you aren't already using it, here's an explanation: Composer is package manager for PHP libraries. Instead of manually downloading a library, you use Composer to download it, and it adds a reference to the library to a configuration file called "composer.json". Later, you can run the "composer outdated" to see if libraries have newer versions, and "composer update" to download and install these. Composer also manages autoloading classes.

Use autoloading classes. No more "include('../lib/foo/bar.class.php')". Composer writes a class autoloader for all its packages. You can also write your own classes as projects, and have Composer manage autoloading for those as well. Autoloading, combined with namespaces, almost completely replaces the "include" statement.

Use tests. Use a testing library like PHPUnit or SimpleTest and write unit tests. How else are you going to get a signal when a change in a library that you're dependent on breaks your code? You can't manually test the entire website each time you upgrade (which is probably why upgrades don't happen). Use Selenium and PhantomJS to write tests for forms and pages. These don't need to be elaborate - just see if the page works.

Use GitHub. I used it, but didn't realize for a few years that the right way to use it is with package management, testing, and git's forking. If you find a bug in a dependency, you fork the project, clone the fork to your dev environment, and then edit composer.json to point to your development copy of the package. You are now a downstream developer! You then write a test case demonstrating the bug, fix the bug, push the changes to GitHub, and submit a pull request. The pull request is a message to the upstream developer to pull the bugfix into their code. Once the bugfix is accepted, you can delete your clone, delete your fork, and re-establish the original dependency.

Use a skeleton. I admit that I don't do this, but using a canned directory structure is useful. Just like using an MVC framework is useful (another thing I don't regularly do). It keeps your files and directories consistent across projects.

Maybe use Twig. It's the templating language that seems to keep growing, ever so slowly. I haven't gotten the Twig religion yet, but it's gonna happen soon. Twig is based on Jinja2, a Python templating library, Jinja2 is, in turn, based on the Django templating library. The syntax is similar to Handlebars, but is more "English-like". There's a version for Javascript, as well, though it's not super popular there. (There's also a dead version called Swig, which has an unfortunate name clash with SWIG. Twig has revived and is being used again.)

Why use a templating library, when PHP is a templating language? Here are the key features that make Twig (and the others) interesting:

  • Template inheritance - like "include" flipped inside-out. Your pages have references to layouts, and only need to output blocks within that layout. So all the layout code is external to your view. Twig knits the layout and your output into a page. This is a weird feature, but you'll get used to it.
  • Include - well, obviously, it has this. Inheritance + Include is just enough to allow clean decomposition of the HTML code into small files, so you're less prone to errors. Also, note that all HTML files can be "validated" for closing tags by any pretty-printing text editor in HTML mode because Twig tags don't look like HTML tags. Contrast this with PHP code blocks, which look like a huge HTML tag. (Twig tags look like {{ name }} and {% for %}.)
  • Filters - You can use pipe (|) to perform simple transformations of your output strings. This can take all that code out of your classes. That's better separation of the view from the controller! (Yes, you can create filters, too. It's all out of your controller.)
  • Crossplatform - you can use the templates in other frameworks, at least in Express and Django. Ruby on Rails is still all about ERB or HAML.

Use Markdown. Don't just use it, support it as an input format. Why? Because it's really easy to learn, supports programmers by making it easy to insert code examples :), and produces valid XHTML as output. Yes, Markdown is a great way to author valid HTML, and it's a good way to assure that input to your program is converted into valid HTML. Normal Markdown passes HTML through, too, but you can filter these out with strip_tags(). The current popular library is PHP Markdown Extra.

Support INI Files. This isn't a best practice - but it's one I like. The trends have gone toward JSON and YAML, but I think the simplicity of INI files wins. It's just hard to make syntax errors with INI files. JSON syntax errors are inevitable, but they usually get caught. YAML syntax errors are also inevitable, but they don't get caught, which is even worse. INI wins.

Use frontend JS tools. They take a while to learn, but CSS compilers and Javascript minifiers are useful. Grunt and Gulp can take you assets and strip metadata, and copy them into specific places. These are all "compilation" tools for the frontend part of your site. Grunt and Gulp can even watch files and run the tools automatically, and even run tests automatically. It hideous stuff, but necessary.

For a long time, I used shell scripts and make, instead of using Grunt, mainly because the config file format looked like a mess (and it is a mess). This was a mistake. Grunt (and Gulp) is the correct tool for web development.

Try using Vagrant and Ansible. Yes, more stuff to learn. Vagrant is a tool that helps set up virtual machines. It helps keep your projects separate, and also runs code within an Linux environment (and Ubuntu LTS version, generally), so it can be run as if it's in the target environment. It's useful when you need to run databses, too.

Ansible isn't super-important for programming, but it's one of several tools to set up and deploy a controlled platform. I learned it for devops, but find that it's worth spending time to write install scripts because you can bring up clean environments in a few unattended minutes rather than 15 to 30 minutes of concentration.

Travis CI or another CI. Once you get the hang of VMs and config scripts, continuous integration isn't far behind. You run tests by creating a VM, running the installer scripts, then running the tests. Travis CI makes it easy by having some canned setups, and triggering form GitHub.

The rest of this, you can ignore. It's the rantings of a madman.

nginx? Nah. I've used both nginx and Apache, and for most situations, Apache is better. Nginx has better performance, but I find that keeping it running requires something like DJB's "supervise" or another task watchdog, which you must configure. Running PHP code requires using the php5-fpm module. Apache magically supports PHP code, and stays running.

NoSQL? Sure, if you know the right use cases. If your requirement is to have 100,000 page websites, it's good. If your requirement is to operate a store with 10,000 catalog items with multiple ways to categorize the items, you're almost certainly going to use SQL, and maybe use NoSQL to store pages. I can't explain it in one paragraph. They're very different products.

REST API?. If it's just GET and POST, I think any framework, or no framework at all, is fine. Once you get into full-featured REST, I have no advice. Apigility looks interesting. With REST APIs there's all this other stuff to deal with, like headers, content type negotiation, CORS, different encodings, and verbs besides GET and POST (like OPTIONS, HEAD, PUT, DELETE, arbitrary verbs, etc.). PHP doesn't support this stuff well, so a framework wraps up the ugliness. I could go on for paragraphs about this stuff.