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.