<<

How to Use PHP , Part 1: The Basics

Author: Craig Buckler

Namespaces are one of the most significant changes in PHP 5.3. They will be familiar to tag">C# and developers, and they are likely to change the structure of PHP applications for the better. Why Do We Need Namespaces?

As the size of your PHP code library increases, there is increased risk of accidentally re-defining a function or class name that has been declared before. The problem is exacerbated when you attempt to add third-party components or plugins; what if two or more code sets implement a ‘Database’ or ‘User’ class?

Until now, the only solution has been long class/function names. For example, WordPress prefixes every name with ‘WP_’. The Zend Framework uses a highly descriptive naming convention that results in long-winded class names such as Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive .

Name collision problems can be solved with namespaces. PHP constants, classes, and functions can be grouped into namespaced libraries. How are Namespaces Defined?

By default, all constant, class, and function names are placed in the global space — like they were before PHP supported namespaces.

Namespaced code is defined using a single keyword at the top of your PHP file. It must be the first command (with the exception of declare ) and no non-PHP code, HTML, or white-space can precede the command, e.g.

1.

The code following this line will be assigned to the ‘MyProject’ namespace. It is not possible to nest namespaces or define more than one namespace for the same code block (only the last will be recognized). However, you can define different namespaced code in the same file, e.g.

1.

Although this is possible, I would advise against it: retain your sanity by defining a single namespace per file.

Sub-namespaces PHP allows you to define a hierarchy of namespaces so libraries can be sub-divided. Sub- namespaces are separated using a (\) character, e.g.

• MyProject\SubName • MyProject\Database\MySQL • CompanyName\MyProject\Library\Common\Widget1 Calling Namespaced Code

In a file named lib1.php, we will define a constant, a function, and a class within the App\Lib1 namespace: lib1.php

1.

We can now include this code in another PHP file, e.g. myapp.php

1.

No namespace is defined in myapp.php so the code exists in the global space. Any direct reference to MYCONST, MyFunction or MyClass will fail because they exist in the App\Lib1 namespace. To call code in lib1.php, we can add a prefix of \App\Lib1 to define fully- qualified names. The following result is output when we load myapp.php:

1. App\Lib1\MYCONST 2. App\Lib1\MyFunction 3. App\Lib1\MyClass::WhoAmI

Fully-qualified names can become quite long and there are few obvious benefits over defining long class names such as App-Lib1-MyClass. Therefore, in the next article, we will discuss aliasing and take a closer look at how PHP resolves namespace names. How to Use PHP Namespaces, Part 2: Importing, Aliases, and Name Resolution

In part 1 , we discussed why PHP namespaces are useful and the namespace keyword. In this article, we examine the use command and the way PHP resolves namespace names.

For the purposes of this example, we will define two almost identical code blocks; the only difference is their namespace: lib1.php:

1. lib2.php:

1.

There is a little PHP terminology to understand before we begin…

Fully-qualified name Any PHP code can refer to a fully-qualified name — an starting with the namespace backslash separator, e.g. \App\Lib1\MYCONST, \App\Lib2\MyFunction(), etc. Fully-qualified names have no ambiguity. The initial backslash operates in a similar way to a file ; it signifies the ‘root’ global space. If we implemented a different MyFunction() in our global space, it could be called from lib1.php or lib2.php using \MyFunction() .

Fully-qualified names are useful for one-off function calls or object initialization. However, they can become impractical when you are making lots of calls. As we will discover below, PHP offers other options to save us from namespace typing cramps.

Qualified name An identifier with at least one namespace separator, e.g. Lib1\MyFunction().

Unqualified name An identifier without a namespace separator, e.g. MyFunction(). Working Within the Same Namespace

Consider the following code: myapp1.php:

1.

Although we include both lib1.php and lib2.php , the MYCONST, MyFunction, and MyClass will only reference code in lib1.php . This occurs because the myapp1.php code is within the same App\Lib1 namespace: result:

1. App\Lib1\MYCONST 2. App\Lib1\MyFunction 3. App\Lib1\MyClass::WhoAmI Namespace Importing

Namespaces can be imported with the use operator, e.g. myapp2.php:

1.

Any number of use statements can be defined or you can separate individual namespaces with a comma. In this example we have imported the App\Lib2 namespace. We still cannot refer directly to MYCONST, MyFunction or MyClass because our code is in the global space and PHP will look for them there. However, if we add a prefix of ‘Lib2\’, they become qualified names; PHP will search through the imported namespaces until it finds a match. result:

1. App\Lib2\MYCONST 2. App\Lib2\MyFunction 3. App\Lib2\MyClass::WhoAmI Namespace Aliases

Namespace aliases are perhaps the most useful construct. Aliases allow us to reference long namespaces using a shorter name. myapp3.php:

1.

The first use statement defines App\Lib1 as ‘L’. Any qualified names using ‘L’ will be translated to ‘App\Lib1 ′ at compile-time. We can therefore refer to L\MYCONST and L\MyFunction rather than the fully-qualified name.

The second use statement is more interesting. It defines ‘Obj’ as an alias for the class ‘MyClass’ within the App\Lib2\ namespace. This is only possible for classes — not constants or functions. We can now use new Obj() or run static methods as shown above. result:

1. App\Lib1\MYCONST 2. App\Lib1\MyFunction 3. App\Lib1\MyClass::WhoAmI 4. App\Lib2\MyClass::WhoAmI PHP Name Resolution Rules

PHP identifier names are resolved using the following namespace rules. Refer to the PHP manual for more information.

1. Calls to fully-qualified functions, classes or constants are resolved at compile-time.

2. Unqualified and qualified names are translated according to the import rules, e.g. if the namespace A\B\C is imported as C, a call to C\D\e() is translated to A\B\C\D\e() .

3. Inside a namespace, all qualified names not already translated according to import rules have the current namespace prepended, e.g. if a call to C\D\e() is performed within namespace A\B, it is translated to A\B\C\D\e() .

4. Unqualified class names are translated according to current import rules and the full name is substituted for short imported name, e.g. if class C in namespace A\B is imported as X, new X() is translated to new A\B\C() .

5. Unqualified function calls within a namespace are resolved at run-time. For example, if MyFunction() is called within namespace A\B, PHP first looks for the function \A\B\MyFunction(). If that is not found, it looks for \MyFunction() in the global space.

6. Calls to unqualified or qualified class names are resolved at run-time. For example, if we call new C() within namespace A\B, PHP will look for the class A\B\C. If that is not found, it will attempt to autoload A\B\C. How to Use PHP Namespaces, Part 3: Keywords and Autoloading

In parts 1 and 2 of this series, we looked at PHP namespace basics , the use operator, and name resolution . In this final article we discuss some of the more advanced namespace options. The __NAMESPACE__ Constant

__NAMESPACE__ is a PHP string that always returns the current namespace name. In the global space it will be an empty string.

1.

The value has obvious benefits during debugging. It can also be used to dynamically generate a fully-qualified class name, e.g.

1. WhoAmI(); // outputs: App\Lib1\MyClass::WhoAmI 11. ?> The namespace Keyword

The namespace keyword can be used to explicitly reference an item within the current namespace or a sub-namespace. It is the namespace equivalent of self within classes:

1. WhoAmI(); // outputs: App\Lib1\MyClass::WhoAmI 10. ?> Autoloading Namespaced Classes

One of the best time-saving features of PHP 5 is autoloading. In global (non-namespaced) PHP code, a standard autoload function could be written:

1.

In PHP 5.3, you can create an instance of a namespaced class. In that situation, the fully- qualified namespace and class name is passed to the __autoload function, e.g. the value of $class_name could be “App\Lib1\MyClass”. You could continue to place all your PHP class files in the same folder and strip the namespace from the string, however, that could result in file name clashes.

Alternatively, your class file hierarchy could be organized in the same way as your namespace structure. For example, a MyClass.php file could be created in the folder /classes/App/Lib1:

/classes/App/Lib1/MyClass.php:

1.

A file in root folder could then use the following code: myapp.php:

1. WhoAmI(); 5. // autoload function 6. function __autoload($class) { 7. // convert namespace to full file path 8. $class = 'classes/' . str_replace('\\', '/', $class) . '.php'; 9. require_once($class); 10. } 11. ?>

Explanation:

1. The class App\Lib1\MyClass is aliased as MC. 2. new MC() is translated to new App\Lib1\MyClass() during compilation. 3. The string “App\Lib1\MyClass” is passed to the __autoload function. This replaces all namespace with file path forward slashes, and modifies the string so the file “classes\App\Lib1\MyClass.php” is loaded.

I hope you found this series of PHP namespace articles useful. Will you be namespacing in your PHP code?