PHP Namespace

30 November -0001
by Justin Klein Keane
June 12, 2006

Recently, while checking some code for problems before rolling it from PHP 4 to PHP 5 I found an interesting bug. A custom library that was being used as a wrapper for Smarty included the following code:

class Interface extends Smarty

While at first glance this seems innocuous, upon further inspection one realizes that 'interface' is a reserved work in PHP 5. Interface is a type of abstract class construct (like 'abstract') that allows a developer to prototype classes. Thus, the above code breaks in PHP 5.

This investigation led me to think about PHP namespace preservation. Even in PHP 5 there is no easy way to preserve PHP namespace to prevent errors like the one I found from occurring. PHP 5 does, however, provide some new ways to protect namespace. Consider the following:

Class A {

	function one() {
		print "This is the first function";
	}
}

Class B extends A {
	
	function one() {
		print "This is the second function";
	}
}

This is a textbook example of method overloading. The following code:

$object = new B;
$object->one();
//prints "This is the second function"

will call the method in Class B rather than in Class A. This problem encapsulates PHP's lack of namespace protection. The only legitimate way to protect Class A's method is by declaring it private and wrapping it in another method. Changing the above classes to:

Class A {

	function one() {
		print "This is the first function";
	}
	function showOne() {
		$this->one();
	}
}

Class B extends A {
	
	function one() {
		print "This is the second function";
	}
}

Will have no effect using:

$object = new B;
$object->showOne();
//prints "This is the second function"

However, if you change Class A to:

Class A {

	private function one() {
		print "This is the first function";
	}
	function showOne() {
		$this->one();
	}
}

Then the code output changes:

$object = new B;
$object->showOne();
//prints "This is the first function"

While this is an interesting work around to protect the methods in Class A it is not a sufficient solution. Utilizing the 'final' keyword explicitly forbids overloading. For instance:

Class A {

	final function one() {
		print "This is the first function";
	}
}

Class B extends A {
	
	function one() {
		print "This is the second function";
	}
}


$object = new B;
$object->one();  //fatal error

will produce a fatal error. In this way the method becomes protected, but the result can be ugly. The problem with this approach is that methods can't be extended either.

Utilizing PHP 5's new native functions (__construct(), __destruct(), __get(), and __set()) can help preserve methods, but not custom methods. Even declaring a method private will not protect it from being overloaded.

One way to end run these problems is to develop a robust naming convention and then adhere to it strictly. In database development it is common to preface a table column with the table name and an underscore to prevent collision with reserved words. For instance, in MySQL 5 'desc' is a reserved word, but could conceivable be used as an abbreviation for 'description'. Prefacing a column name with a table name, for instance 'user_desc', avoids problems with reserved keywords. Utilizing a similar approach in PHP allows for methods to be overwritten, but reduces the likelihood that methods would be inadvertently overwritten. For instance:

Class A {

	function a_one() {
		print "This is the first function";
	}
}

Class B extends A {
	
	function b_one() {
		print "This is the second function";
	}
}

Provides for a class hierarchy that protects class methods from being unintentionally overwritten while still allowing the flexibility to purposely overwrite or extend class methods.