Introduction
Namespaces are a way to make your class names and function names unique so they won't conflict with other libraries that may be using the same class and function names.
In this unit you'll learn how namespaces help avoid naming conflicts.
Packages
When you build any application, it's always a good idea to reuse code as much as you can, instead of reinventing the wheel and possibly introducing errors that could have been avoided.
Modern PHP applications contain dozens or hundreds of small code libraries called packages, often distributed via the Packagist repository. While some packages are only suitable for a single application, many packages are generic and can be reused across different applications.
Package examples
The psr/log package helps developers create uniform logging systems, and is used (depended upon) by more than 5000 other packages and applications, including Drupal.
The drupal/coder package is a library for automated Drupal code reviews and coding standard fixes. It is used by Drupal itself and by external tools that automate Drupal code updates and quality checks.
Symfony's symfony/console package lets you to create command-line commands that can be used for any purpose, including recurring tasks, deployment tasks, and import/export tasks.
Problem: naming conflicts.
Have you ever noticed how people in the United States often say they live in "Paris, Texas" or "Flint, Michigan"?
They qualify the name of their city by adding the name of the state, to avoid confusion with cities by the same name in other US states.
You could say that "City Name, State name" is the fully qualified name of a city. There may be many cities named Paris, but there's only one Paris, Texas.
Naming conflicts in code.
Even if your application doesn't use many packages, it's still possible that some of them use the same class names or function names.
If not handled correctly, this can lead to naming conflicts, which cause serious trouble.
Consider the following scenario:
- PHP has a built-in
strtoupper()function which transforms a string into capital letters. - We want to create our own
strtoupper()function that transforms the first letter into uppercase and the other letters into lowercase. - There is already another built-in string function for this named
ucfirst(). - So our goal is to make our own
strtoupper()function and make it produce the same output asucfirst()does.
When we try to define a function named strtoupper(), an error message is produced because PHP already has a built-in function named strtoupper():
Example 1
// Transform string.
// Make first letter uppercase and the rest lowercase.
// This will produce an ERROR.
function strtoupper($str) {
return ucfirst($str);
}
print strtoupper('hello world');Output:
PHP Fatal error: Cannot declare strtoupper().
Solution: namespaces
Namespaces solve this problem. They let you reuse function or class names that have already been declared elsewhere, but without causing a naming conflict.
Here's how it works: use the namespace keyword to declare a namespace of your choice above your code:
Example 2
The strtoupper() function now belongs to the MyTools namespace, which makes the function's fully qualified name \MyTools\strtoupper().
In a PHP code file, as soon as you have declared a namespace, all the functions, classes, interfaces, and traits you define will automatically belong to that namespace.
Any time you work in a namespace - any time you write code in file where a namespace was declared - the functions, classes, etc defined under that namespace will have priority when called.
This is demonstrated in the strtoupper() example: our version of strtoupper() is used instead of the default version of strtoupper().
But what if you have redeclared an existing function but want to use the original one? Use the fully qualified name:
The built-in version of strtoupper() is defined under the global namespace \, so its fully qualified name is \strtoupper()
Our version of strtoupper() is defined under the MyTools namespace, so its fully qualified name is \Mytools\strtoupper().
If this confuses you, here's a different way of looking at it:
If you do NOT declare a namespace in your code file, PHP assumes the global namespace \.
As a consequence, when you call any function, such as strtoupper(), PHP will combine the implicit \ namespace with the function name strtoupper(), and call \strtoupper().
On the other hand, if you do declare a namespace such as MyTools, redefine strtoupper(), and then call strtoupper(), PHP will combine your explicit namespace MyTools with the function name strtoupper() and call \MyTools\strtoupper().
If you now want to call the original strtoupper() function, you need to use the fully qualified name to tell PHP which one to use: \strtoupper() instead of strtoupper().
Comparing usage examples
Let's look at a few practical examples to illustrate what was just explained.
At the end of the examples you'll find an activity that asks you to explain the output of each of the examples.
Example 3: using the built-in \strtoupper() function
Example 4: Redeclaring strtoupper() outside a namespace (ERROR)
Example 5: Redeclaring strtoupper() inside a namespace
Example 6: Redeclaring inside a namespace but calling the original function
Example 7a: Calling a namespaced function from outside its namespace
Example 7b: Calling a built-in function from the global namespace
Example 7c: Calling a built-in function from the global namespace, explicitly using the global namespace
Activity
For examples 3 to 7c, explain in your own words which version of strtoupper() was used, and why.
Multi-level namespaces
Namespaces often have multiple levels to help organize the various code files, classes, etc.
For example, as of Drupal 8, each module's namespace is \Drupal\name_of_the_module, and depending on what the module actually does you will find namespaces like
\Drupal\name_of_the_module\Plugins\Drupal\name_of_the_module\Plugins\Block\Drupal\name_of_the_module\Plugins\form\Drupal\name_of_the_module\Controller
\Drupal\name_of_the_module\Plugins\Block\MyCustomBlock would be the fully qualified name of a MyCustomBlock class inside the \Drupal\name_of_the_module\Plugins\Block namespace.
And and the fully qualified name of a create() method inside that class would be \Drupal\name_of_the_module\Plugins\Block\MyCustomBlock::create.
In other words, any time you want to refer to a specific method of a namespaced class in documentation like this course, you can provide the fully qualified name of the class, followed by the scope resolution operator ::, followed by the method name. That way it's clear and unambiguous which exact method on which exact namespaced class you're talking about.
Note that namespaces look a bit like web addresses or folders on a hard drive. The actual code files that contain classes, functions, etc is often organised in folders that follow the same structure as the namespace, but this is NOT mandatory: it's technically possible to place all your code files in one single directory, and still use multi-level namespaces to organise them as if they were stored in different folders.
In general you're free to choose your own namespace names and levels for your own code, but if you write code in the context of a framework like Symfony or Drupal, you also have to follow certain rules about the name and structure of your namespaces, and the underlying folder structure.
Refer to your framework's documentation for details.
Example
In this example we declare two namespaces:
MyTools\StringsMyTools
We defined strtoupper() inside the MyTools\Strings namespace, so that function's fully qualified name is \Mytools\Strings\strtoupper().
We created a User class inside the MyTools namespace, so the class' namespace is \MyTools\User, and it contains a setName() method.
Inside \MyTools\User::setName() we call strtoupper().
Which version of strtoupper() do you think will be called? \strtoupper() or \MyTools\Strings\strtoupper()?
The answer is: \strtoupper().
Why? Because we're working in the MyTools namespace, and directly inside the MyTools namespace there exists no strtoupper() function: \MyTools\strtoupper() does not exist.
However, \Mytools\Strings\strtoupper() does exist.
But that version of strtoupper() lives in the Mytools\Strings namespace, not in the MyTools namespace where we are currently working.
PHP tries to find a strtoupper() function in the MyTools namespace, doesn't find one, then tries in the global namespace, and there it successfully finds \strtoupper().
If instead of \strtoupper() we wanted to call \Mytools\Strings\strtoupper() from inside \MyTools\User::setName(), we can do two things:
Option 1
We provide the fully qualified name \MyTools\Strings\strtoupper() to avoid any confusion.
Option 2
We provide a partial, relative namespace: Strings\strtoupper().
When PHP tries to figure out the fully qualified name for Strings\strtoupper(), it first checks if there is a sub-namespace Strings inside the current namespace MyTools.
If there is, it tries to find a strtoupper() function inside the MyTools\Strings namespace.
If there is no \MyTools\Strings\strtoupper(), PHP will check if there is a Strings namespace inside the global namespace: it checks if \Strings\strtoupper() exists.
If that can't be found either, PHP will return an error: "undefined function Strings\strtoupper()"
Namespace resolution
As demonstrated in the previous section on multi-level namespaces, there is a consistent and predictable mechanism that PHP uses to figure out which version of a class or function you want to use.
If you don't provide a fully qualified name for the function you're calling, PHP will prefix the given function name with the name of the current namespace. If you're not in a specific namespace, you're in the global namespace.
→ Study example 8 carefully and don't skip the activity that follows.
Example 8
Activity
For examples 8a to 8f, which version of strtoupper() gets called?
If only one option is given, is it a valid option (will it work), or will an error ("undefined function") be emitted?
Summary
- Namespaces provide a safe space for your methods and classes so their names don't conflict.
- Namespaces let you organise your functions and classes logically, even if they are all located in the same single physical directory.
- A function or class' fully qualified name consists of a backslash, followed by its namespace, followed by its name: function
create()in namespaceMyTools→\MyTools\create(). - If you provide a partial namespace (one that does not start with a backslash), PHP will prefix it with the name of the current namespace.
- If you're not working in a specific namespace, you are working in the global
\namespace.