Understanding namespace in PHP

Understanding namespace in PHP

In Computer science, namespace is basically used to make sure that classes/objects should be uniquely identified. Because when we worked with a large set of codebase then there might be a possibility that same name classes exist. So, when we include them and access them via creating an object then it conflicts. Inside understanding namespace in PHP post, we’ll go through each step one by one.

In this post, we understand namespace with practical examples and we are also gonna see different ways of using it which will solve our name collision problem.

Why use Namespace?

When we include open source or custom packages in our projects like PDF, Excel-sheet and so on then there might be a situation that two classes are having same method/const name. Or there may be same class is present in the package that is similar to what we have in our project.

Consider in an example of two different classes located at two different locations in the codebase, and those are autoloaded in the code using include/require/include_once/require_once method.

At this time, we don’t know whether two classes will have the same class name (for the obvious reason that we can’t check each and every file for the same function existence). So when we executed our code then PHP surprise us with the following Error.

Fatal error: Cannot declare class class_name, because the name is already in use in file_name.php on line line_number

So, to solve this problem, in PHP 5.3, namespace was introduced. Those who have worked on JAVA OR C#, they must know it already.

How Namespaces are defined?

Namespace comes with very basic syntax. They are defined at the top of each PHP file. A namespace can be declared with the keyword Namespace. .Here is the example of a namespace.

<?php

// define a namespace event

namespace event;

As per the PHP coding standards suggested by PHP-FIG, Namespace should contain least one level: a top-level vendor name and it is advised that projects that using PHP >=5.3.0 MUST use formal namespaces and it should be defined at the top of the file before any other code except define().

In the above syntax, we just defined one namespace event. We can also define as many namespaces in the file as possible. But there is a restriction of using multiple namespaces for the single block of code.

<?php

namespace event;

// code for event related tasks

namespace student;

// code for student related tasks

.. and so on

// Using namespace with curly bracket

namespace studentDetails {

// code for studentDetails

}

In the above examples, we have defined three namespaces, two with the normal declaration and one with a curly bracket. We can define as many names in a file as possible. In the third example, we have encapsulated code inside the curly bracket which is completely optional. In fact, it is advisable to use one namespace per file to look code more readable and cleaner.

<?php

class eventDetails {

}

In the above example, we have created simple class eventDetails and its scope is global. Being at the global scope, we can create an object of this class and class can be matched with other identical class which can cause conflict issue.

<?php

namespace event;

class eventDetails {

}

Note that, we have defined namespace event to class eventDetails which means that now class eventDetails is within the namespace event.
Now when we try to create an object of class eventDetails then it will throw an Error because now class eventDetails is not bound to global namespace rather it is within namespace event. So to access class, we need to make necessary changes in the object creation and that will show to which namespace particular class belongs.

$obj = new \event\eventDetails();

As we can see, we have added namescape event and \ (backslash) before class eventDetails. Now we have class eventDetails within event namespace.

Suppose we have a class eventDetails which is declared within the global scope like-

<?php

class eventDetails {

}

Now, at the very next line we defined a namespace and tried to create an object of this class then it will throw an error.

namespace event;

$obj = new eventDetails();
Fatal error: Uncaught Error: Class 'event\eventDetails' not found in

Why this Error?

Because currently class eventDetails does not lie within namespace event and PHP will find the class eventDetails within the scope of event namespace. But as class eventDetails is defined with the global scope.Hence it will throw a fatal Error saying that class ‘event\eventDetails’ not found. The Error itself says that class foo should be defined within namespace event itself.

So the question is how can I access the class defined in global scope within namespace event. We can somehow relate same with function that is trying to access global variable within function. So, in this case will add \ before the classname that will try to find the class in the global scope and if found, then it will create an object.

What if we want to access one namespace within another namespace?

Yes we can access one namespace within another namespace by defining complete namespace path and then creating an object of the class-

<?php

namespace event;

class eventDetails {

}

namespace yearParty;

$obj = new \event\eventDetails();

So basically, every time we require to access the namespace global OR defined, then we need to add \ before the namespace which we are trying to access

Now, what will happen we define two namespaces to the same block of code. In this case, it will give an Error. Here is the example-

// event.class.php

<?php

namespace eventClass;
namespace eventClassCode;

class event
{

    public function getEventId()
    {
        return "execute foo->getEventId()";
    }
}
<?php

include "event.class.php";

$obj = new event;
echo $obj->getEventId();
// OUTPUT

Error: Class 'event' not found

Without namespace, this above error would have never be triggered. But with namespace, we have to make sure that while creating an object, class name should be fully qualified. It means now we’ve to just use the namespace before the class name. In this way, we can now never face an issue of class name conflict. This is just a small example, with big codebase name of the namespace comes with fully qualified directory names like-

 namespace "directory1\directory2\directory3\namespace_name";

So, we can modify above code by using fully qualified namespace as follows-

<?php

include "event.class.php";

$obj = new eventClassCode\event;
echo $obj->getEventId();
// OUTPUT

execute event->getEventId()

We can also notice that, we have defined two namespaces one after another. So for the next block of code PHP will consider the later namespace rather than the first one. Hence, we used eventClassCode namespace to create the event class object.

Declaring sub-namespace in PHP

When working with a large codebase, we often divide our code based on their functionality. e.g., take an example of Symfony, we imported a vendor folder to work on HTTP related operation like curl request. We will create a file like this-

Understanding namespace in PHP

So, with above directory structure, we can differentiate curl file with other same file if present.
Syntax-

namespace symfony\vendor\php-http\src\Curl;

Common Misconception about Namespace

The biggest OR the common misconception about namespace is that we think that by specifying namespace at the top of the page, we do not require to include that file in the codebase using functions like include/require/include_once/require_once.

Here, most of us think that PHP will internally include that file in the codebase and whenever there is a need to create an object then we do not need to worry about adding it in the codebase.

No, this is not the way PHP namespace works.

As mentioned above, PHP uniquely identifies files based on the namespace defined at the start of each file. So including files before identifying it uniquely is more important.

With the release of composer, PHP has an advantages of including dynamic libraries based on the requirement and yes auto-loading it while project boots up is also more important.

Understanding namespace in PHP with Example

<?php
// curl call
namespace Http\Client\Curl;

class Client
{

    const CURL_DOMAIN = 'https://example.com';

    function curl_request()
    {
        $ch = curl_init(self::CURL_DOMAIN );
        $fp = fopen("json_response.txt", "w");

        curl_setopt($ch, CURLOPT_FILE, $fp);
        curl_setopt($ch, CURLOPT_HEADER, 0);

        curl_exec($ch);
        if (curl_error($ch))
        {
            fwrite($fp, curl_error($ch));
        }
        curl_close($ch);
        fclose($fp);
    }
}

$objClient = new Client;

Using use statement

When dealing with large namespace, it becomes very confusing to write long tail namespace while using it. So to solve this problem, PHP has provided use keyword to import other namespaces into current namespace so that we can effectively use outside namespace.

With use, we do not need to add long namespace while creating an object. Now it Allows us to instantiate it by name only. All the hectic of keeping in mind about adding backslash and then adding perfect path to the namespace is not required.

use keyword in namespace in php
use keyword in namespace in php

So, when importing any namespace into another namespace we need to use , use keyword and namespace. That’s it. As shown in the above example, we have defined namespace \vendor\src\client\classes and then at the end we added classname curl. Now we can access this class easily. All we have to do is to create an object of class curl only.

$obj = new curl();

Pretty Easy, right?

If we want to alias this imported namespace as out requirement then we can do that as well like this-

use \vendor\src\client\classes\curl as curl_class;
<?php
// avenders.php

namespace src\marvel;

class avengers
{

    public $list = ['Iron Man', 'Captain America', 'Hulk', 'Thor'];

    public function characters()
    {
        return $this->list;
    }
}
<?php
// marvel.php

namespace comics;

include "avengers.php";

use src\comics\avengers;

class Marvel
{
    public function getAvengersList()
    {
        $objAvengers = new avengers();
        return $objAvengers->characters();
    }
}

$obj = new Marvel;
print_r($obj->getAvengersInfo());
// OUTPUT

Array ( 

      [0] => Iron Man 
      [1] => Captain America 
      [2] => Hulk 
      [3] => Thor 

)

Class name resolution using ::class

PHP 5.5 has introduced new addition to namespace which is class name resolution.

This was mainly added to extend the usability of namespace and get its related class name using ::class.

<?php


namespace App\Models;

class UserModel
{

    public function getUser()
    {
        return ["id"=>1, "name"=>"John", "address"=>"NJ, USA"];
    }
}


namespace App\src;

class employee {

    public function employeeInfo(){
        return $this->getUserInfo(\App\Models\UserModel::class);
    }
    
    private function getUserInfo($userModel) {
        $objUserModel = new $userModel;
        
        return $objUserModel->getUser();
    }
}

print_r((new employee)->employeeInfo());

In the above example, we have created two classes in which one is UserModel and another is an employee class. So from UserModel will return user information and employee class contains employeeInfo() method to get user information from getUser() function. But we have passed the UserModel class name by using ::class. This will give class name through which we’ll create an object and then will fetch our user’s information using getUser() function.

One thing to notice that, we do not require to use use statement where we include namespace+classname. This has been reduced to namespace+classname::class which will return class name itself.

Use in-built functions in use statement

We can also use PHPs inbuilt array and string functions in different ways. Well this is an optional but there is a provision to use.

Let’s see code in action and then we’ll understand in step by step

<?php

namespace src\vendor\library;

use function str_replace as replace;

$a = "Python";
$b = "PHP";
echo replace($a, $b, "Python is the best language");

We have seen an extraordinary example of use of in-built function using use statement.

In above case, we define str_replace using use statement. Please remember to add function before str_replace to let PHP know that we are using its in-built function and also we can add alias to this (which is optional)

Conclusion-

Namespace gives us flexibility to make same name class to be available at different module. Here in this post, we understand namespace in PHP with different examples and saw its benefits. With legacy codebase it’s very important to use replace old style of code writing with new and with code size increasing day by, we can’t afford to find needle in the big haystack.