Namespaces Best-practice in PHP 5.3
Since PHP 5.3 we finally can take use of the long wanted namespaces, which help us to keep the global namespace clean and save some work when declare class names.
PHP 5.2 is released in its last versions, so it is probably that many hosters and developers switch to PHP 5.3. Also Zend Framework and Symphony 2.0 uses namespaces, so they require PHP 5.3.
But how to use namespaces in an accurate way? I'll try to explain my experiences I've made while developing Gitty here.
For the this article you should have read the PHP manual about namespaces.
Dos and Don'ts
use PascalCase
When _ was the namespace separator of choice, everyone used PascalCase for declaring namespaces
I would recommend to continue doing so: \lib\mynamespace\MyClass far better: \Lib\MyNamespace\MyClass.
Escaping of namespaces inside strings
You should use two backslashes when naming namespaces inside string in all cases. Examples:
$class1 = '\\Namespace\\Class1'; $class2 = '\\Namespace\\SubNamespace\\Class2';That avoids parsing errors and the adjacent search for the error.
Avoid naming the global namespace
Instead of naming the global namespace for classes or functions you should add an alias with use. Doing so allows other developers to rename the namespaces or replacing the alias with their own.
Example
Instead of the following class:
namespace MyNamespace; class SaveConfig { protected $config; public function __construct($config) { $this->config = new \OtherNamespace\Config\Ini($config); } }it would be far better to do:
namespace MyNamespace; use \OtherNamespace\Config as Config; class SaveConfig { protected $config; public function __construct($config) { $this->config = new Config\Ini($config); } }When we change our library, so the namespace OtherNamespace is now named NewOtherNamespace, we only need to adjust the use statement. That allows developers to use their own namespace:
use \MyNamespaceOther\Config as Config;Generally you can say, that prefixing \ a class declaration should be avoided. On many declarations of a class the use saves some work.
If you should use this also for php classes and functions is a matter of taste. In case MySqli is moved into its own namespace it would lighten adjusting: use \DatabaseAdapter\MySqli as MySqli;.
use __NAMESPACE__
Also generally it's a good idea to use __NAMESPACE__, if you want to reference to other functions, classes etc.
Example
Lets assume we want to add an adapter for a class dynamically and use this adapter name also outside the namespace. Adapters is thereby a namespace inside ExampleNamespace. So let's build our a adapter with the help of __NAMESPACE__ together:
namespace ExampleNamespace; class MyClass1 { private static $adapterClass = null; public static function setAdapterClass($class) { self::$adapterClass = $class; } public static function getAdapterClass() { if (null === self::$adapterClass) { self::$adapterClass = __NAMESPACE__.'\\Adapters\\MyAdapter'; } return self::$adapterClass; } }When now somebody want to rename ExampleNamespace, he only needs to change namespace ExampleNamespace;, optionally the file and folder names and namespace ExampleNamespace\Adapters; inside of the adapters. He doesn't need to rename ExampleNamespace inside of MyClass1. That avoids errors.
Fallback
If you should name the global namespace when using global functions and constants inside a namespace or let the fallback do all the work, is something you should decide in your team or for yourself.
Even if it doesn't look so nice to prefix all global functions and constants with \, it's a bit cleaner to do so. While adding namespaces to old librays it more a nice-to-have, since the fallback it really good optimized. In a small benchmark the fallback was only few seconds slower, even on hundred thousand cycles.
Hacking
Unfortunately PHP doesn't allow using constants while declaring class properties. As an example I'll re-use my example with the adapters:
namespace ExampleNamespace;
class MyClass2
{
public static $adapterClass = null;
public static function setAdapterClass($class)
{
self::$adapterClass = $class;
}
public static function getAdapterClass()
{
return self::$adapterClass;
}
}
$__className = __NAMESPACE__.'\\MyClass2';
$__className::$adapterClass = __NAMESPACE__.'\\Adapters\\MyAdapter';
unset($__className);Even if this is a unpurified, you're able to declare public properties, while in parse time. Setting private or protected properties must still be done inside of getAdapterClass(), like shown under use __NAMESPACE__.
Published at: August 11, 2010 – Last change: August 11, 2010
