BUG: Constructors, Interfaces, and Abstracts Don’t Mix Well

I just discovered a bug today in PHP 5.1 (haven’t confirmed if it was fixed in newer versions). When trying to enforce interface arguments on constructors, PHP behaves unexpectedly. Normally, interfaces allow you to enforce argument counts or types in child class methods, but not with the constructor (and probably destructor).

Crash course on interfaces: An interface lets you as a developer dictate a standard for a class. For example, you might write an interface class for interacting with your class. Then other people who want to interact with your class would “implement” your interface class. This would force their classes to have a certain set of methods, of which you dictate their names and argument counts (and types). This way, your class is always guaranteed these implementer classes have certain key methods. In the real life example, it’s like saying an interface for a Car would have methods like brake($amount), gas($amount), steer($direction), etc, and the User class would be able to have a guaranteed way of interacting with the Car object (i.e., $user->getCar(‘Ferrari’)->steer(‘left’)). Abstract methods exist in abstract classes and are essentially the same thing. Read more about these here and here.

First, here is an example of a typical interface:

class ExampleClass {}

interface TestInterface {
	public function output(ExampleClass $var);
}

class Test implements TestInterface {
	// error, no output() method was defined
}

The following fails too:

class ExampleClass {}

interface TestInterface {
	public function output(ExampleClass $var);
}

class Test implements TestInterface {
	public function output($var) {} // error, wrong argument type
}

Here is the same example but with the __construct method instead:

class ExampleClass {}

interface TestInterface {
	public function __construct(ExampleClass $var);
}

class Test implements TestInterface {
	// error, no __construct() method was defined
}

Up to here, it works as expected. However, if you define the constructor, the __construct method argument datatype/count checks go out the window:

class ExampleClass {}

interface TestInterface {
	public function __construct(ExampleClass $var);
}

class Test implements TestInterface {
	public function __construct() {} // NO ERROR
}

Despite the data types and argument count being off, PHP doesn’t care. Even if I define an argument in the constructor, the datatype check is ignored. So the best you can do is force a __construct() definition to be required, but you can’t dictate its arguments (i.e., interfaces for constructor methods are useless). And finally, for those of you really astute readers:

class ExampleClass {}

abstract class AbstractTest {
	abstract public function __construct(ExampleClass $var);
}

class Test extends AbstractTest {
	public function __construct() {} // NO ERROR
}

This problem produces the SAME results if instead of an interface, abstract methods in an abstract parent class are used.

A Great Web Developer is a Great Application Developer

After being a part of the developer hiring process for a while now, I have begun to see what distinguishes an exceptional web developer (the ones that get hired faster than we can even make an offer) and everybody else. Things have changed since 1995 – web development requires actual knowledge of programming!

The problem is that people think web development is somehow easier than other types of development. Nothing is inherently easier about developing an application in PHP than in C++. While I could accuse people who say this as being naive, the truth is that web developers themselves seem to hold this as the truth. In order to excel at being a web developer, one must understand how to develop an application. In other words, there are very different skills required in programming something like Facebook or Digg than for updating Mom’s store website.

First, you must actually understand object oriented programming (OOP). Everybody these days says they “know” OOP. I don’t mean “you read about it in a book” or that you can use a class when necessary; I mean being able to write extensible, modular libraries. This takes time and practice. When people first begin writing classes, they mistake the process for “grouping up functions under one class name in one file.” This is dead wrong and actually counter productive in some cases.

Classes are about automation and simplification. The classic analogy for OOP is a car because it has many parts that make it a whole. But just like the driver has no idea what a crank shaft, piston, or fuel injector does, people using your class should have no idea (nor need to learn why) about the inner workings of your class. All they need to know is that calling one of the few public methods (turn_ignition(), step_on_pedal(), steer()) does a whole lot of cool stuff behind the scenes that makes their life easier. And just like how you wouldn’t want the entire car engine welded together (instead of using bolts and screws), you shouldn’t write humongous class methods that do 1000 things — break it up into digestible parts so that other people can enhance just the pieces they want (see “overloading” below).

When you design a class, you start by listing out things that the class will be used for. Then, you figure out the lowest common denominators between these actions to remove “special, one time cases.” You now have a list of your primary public functions. Everything else in your class should pretty much remain protected or private (discretion is learned with experience). The entire point is that classes are not a group of similar functions, but rather a single conceptual unit.

And when you’re all done with understanding why object oriented programming exists, you must then learn to use Inheritance, and Overloading (some languages) and Interfaces.

Second, you must understand and demonstrate competency with design patterns. At the very least, you should be aware of the Singleton and Factory patterns, which are very commonly used, and for (arguably) good reasons. Knowledge of basic design patterns goes a long way because a time will come when you may need to borrow from one of these concepts when developing your web application. It also means you have a wider exposure to the different types of architectures available to someone writing a library or application.

Last, you must understand scaling issues in growing web applications and how to resolve them. This is probably the rarest trait, but if you have it, you will shine like a rock star. It is important to realize that certain operations are much more costly than others. In today’s world, the CPU is rarely the bottleneck, but there are still bottlenecks. A common instance of this problem is when Word Press blogs go offline because it is slammed by a spike in traffic. That said, the most common type of bottleneck involves the database and often manifests in one of three ways:

  • Each query sent to the database involves some small amount of lag between the web server and the database server. Hundreds of queries on a page will slow down your page loads. On high traffic pages, one less query means thousands of queries a second. Make sure you learn how to do JOIN statements.
  • Each query must use an index in the database. Without this index, a query looking at a large table will bottleneck the hard drive (because it has to search large portions of the disk). Learn how to use the MySQL command: explain.
  • Database tables using MyISAM (instead of InnoDB) risk facing table locking issues. When you run a big or complex update on MyISAM, no other updates can occur on that table until the first one is done. If that table is very large, this may mean someone’s page sits there and loads for a long time (or times out). Typically, one should use a transactional database such as InnoDB.

Other types of common scaling issues are:

  • Session management on the database instead of letting PHP handle it. This is an issue because any large web application has more than one web server which means when a person hits a new page they might be loading from a different web server each time.
  • Managing files generated on the server – such as when a user uploads a file. The issue here is that if a file is created on one server (in a cluster of 100), how do the other servers know it exists? Obviously the solution is to somehow centralize this with a synchronization process or store all of the files somewhere else.
  • How queries can start acting different (much slower) when your tables reach 1M+ rows without proper precautions. Larger tables change things because indexes sometimes stop getting used or slowness that wasn’t apparent before is now very noticeable. (A book could be written here…)

Merely reading and understanding these issues has put you ahead of a bunch of people out there. 🙂

In conclusion, you must re-think the “web developer” as an application developer that happens to work in a browser. I often hear the excuse that these types of advanced concepts can’t be readily applied in small-time applications (such as a simple store-front), but I believe this is simply not true. Virtually every site requires a database connection or a template system (for easy inclusion of header/footer files). Database abstraction and template systems are probably the single best place to use OOP concepts. It simply makes no sense that one would use the raw mysql_query() function in any website, even if it’s just Mom’s baby pictures. Putting these ideas in classes reduces security vulnerabilities and makes development much faster. If the notion of abstracting templates or databases is totally foreign to you, I suggest you start by looking at Smarty or EzSQL.

Happy studying. 🙂