Over the past several months I’ve been following Agile coding principles in my work, as described by Bob Martin and others (see, for example, Clean Code, Agile Software Development, and Growing Object-Oriented Software, Guided by Tests). Applying these principles in PHP presents some challenges. Applying them to WordPress plugin development presents even more challenges. This is the first in a series of posts on how I’m dealing with those challenges. My Google searches about PHP and Agile coding don’t turn up much, so I figure I can break some new ground 😉 . But I don’t consider myself an expert – feedback is welcome.
If you follow the Agile principle of small methods and small classes, your projects will consist of a large number of small files. In Java, this doesn’t matter much – the project is compiled before it’s deployed. But PHP is a scripting language, so it’s compiled on the fly.
require statements can have a moderately expensive performance cost (see here and here). So what’s the best way to include your files for code readability, and for efficiency?
I always use
require_once to include a required file. I don’t use
include, which allows the compilation to proceed even if the file is not found (a class file isn’t going to be optional).
require_once has a reputation for being slower than
require, but this benchmarking indicates otherwise (I wouldn’t consider that an exhaustive study, but it’s enough that I’m not going to lose sleep over it). This way I don’t have to worry if a file has been included somewhere else already. If you have lots of small classes, used in various places,
require_once can save you from that headache.
Where to put your
There are three options:
- The simplest option, and worst from both a performance and code integrity perspective, is to include all your project’s class files in the initializing script. Dependencies between classes will not be evident to someone reading your code. That is, if you tried to use one of the classes in a different project, and that class has dependencies on other classes, the class would fail to compile unless you read through the class to find the dependencies and added them to your new calling script (and then you’d have to manage the dependencies in two places). It’s also unnecessarily wasteful. Any given execution path through your project likely only requires a subset of your classes, so there’s no reason to load them all for every single http request.
- The second and most preferable option is to include all the class files a given class depends on at the top of that class file (before the
classline). This is common practice in languages I’m familiar with. From a readability perspective, the dependencies are clearly stated at the top of the class file. From a performance perspective, you’re only loading what that class needs. And from a flexibility perspective, that class can now be used outside the context of any particular calling script (as long as you package it with what it depends on). Note that if you are doing dependency injection, you’ll be passing in already instantiated objects to the dependent class, so your file includes will be one step removed from the class where the objects are actually used. The simplest way to think about this is to include the class file dependencies wherever there are
newcalls on those classes.
- A third option is something I was doing, until @speno showed me the error of my ways. I put the
require_oncestatement for a class file on the line before calling
newon that class, regardless of where I was in the code. There is no technical problem with doing this – PHP will read the class into memory – it doesn’t matter if you’re inside a method. I did it in pursuit of improved performance: dependent classes are loaded only exactly when they are needed. The problem, however, is that the dependencies are now buried in the code of the class, making the reader of your code do more work to find them (and risking missing them, which leads to bugs…). A tenent of Agile programming is that you optimize for readability first, and that you sacrifice that readability for performance only when there is a demonstrable performance problem to address. What I was doing is an example of premature optimization (and the “gut feeling” optimizations many of us do, like I did, often turn out to not be optimizations at all when you profile the actual performance).
If you do have performance problems, file includes are probably not the first place to look. Database queries are the more common culprit. But if you do need to reduce your hits on the filesystem, you should look at opcode cachers, such as APC (or, for WordPress, the W3 Total Cache plugin) before you contemplate writing hard to read and maintain God objects.
Note: this is a revised version of the original post.