35

I posted some questions previously regarding the use of Namespaces in PHP and from what I got, this example code I have below should be working.

However I am getting errors when I try to use Namespace in PHP like this. Here is the first error when running the code below as is...

Fatal error: Class 'Controller' not found in E:\Controllers\testing.php on line 6

E:\Controller\testing.php File

<?php
use \Controller;

include('testcontroller.php');

$controller = new Controller;
$controller->show();
?>

E:\Controller\testcontroller.php File

<?php
use \Library\Registry;

namespace Controller
{
    class Controller
    {
        public $registry;

        function __construct()
        {
            include('E:\Library\Registry.class.php');
            $this->registry = new Registry;
        }

        function show()
        {
            echo $this->registry;
            echo '<br>Registry was ran inside testcontroller.php<br>';
        }
    }
}
?>

E:\Library\Registry.class.php File

<?php
namespace Library\Registry
{
    class Registry
    {
        function __construct()
        {
            return 'Registry.class.php Constructor was ran';
        }
    }
}
?>

As you can see I tried to make it as simple as possible just to get the Namespace part working. I have tried different variations and cannot seem to figure it out.

6 Answers 6

49

Even when using use statement, you need to specify the namespace of the class you are trying to instantiate. There are a lot of examples here: http://www.php.net/manual/en/language.namespaces.importing.php

To understand it better, I will describe to you how it works. In your case, when you do use \Controller, the whole Controller namespace becomes available to you, but not the classes that are in this namespace. So, for example:

<?php
include('testcontroller.php');

use \Controller;

// Desired class is in namespace!
$controller = new Controller\Controller();

// Error, because in current scope there is no such class
$controller = new Controller();

$controller->show();
?>

Another example:

testcontoller.php:

<?php
namespace Some\Path\To\Controller;

class Controller
{
    function __construct()
    {

    }

    function show()
    {
        echo '<br>Was run inside testcontroller.php<br>';
    }
}
?>

testing.php:

<?php
include('testcontroller.php');

use \Some\Path\To\Controller;

// We now can access Controller using only Controller namespace,
// not Some\Path\To\Controller
$controller = new Controller\Controller();

// Error, because, again, in current scope there is no such class
$controller = new Controller();

$controller->show();
?>

If you wish to import exactly the Controller class, you need to do use Controller\Controller - then this class will be accessible in your current scope.

Sign up to request clarification or add additional context in comments.

6 Comments

Good example, I figured this out last night but good for you to describe it. So I think I would be better off to put all my Library classes into the same namespace like Library and then on the testcontroller above I could use use Library\Classname for each class in my library that I need in that controller so I can then assess them like this new Registry etc... on php.net/manual/en/language.namespaces.importing.php I think it is saying this is importing a global class so I wasn't sure if it was a bad idea
I`m trying to limit dependecies of each class, thats why for me it is not hard to use full qualified name for class.
Thats wrong: With use you also define an alias for a concrete class. In the example use \Controller; new Controller; its not very obvious, but you can try use Vendor\Package\Component\Controller; new Controller. What I mean: Its wrong, that you need to define the namespace of a class in every case. See the link in jasondeavis comment. Its described, how PHP resolves relative classnames.
Read whole my comment. Especially, "If you wish to import exactly Controller class, you need to do use Controller\Controller, and, then, this class would be accessible in your current scope." part.
I am just confuse, why include('testcontroller.php'); when you importing class already by use \Some\Path\To\Controller;?
|
10

Its not that good idea to name the namespace, like the class, because it is confusing (and I think this is what happens here). There moment you define the alias via use Controller this referenes to either a class \Controller, or the namespace \Controller, but your class, because it is within the namespace, is named \Controller\Controller 1

use Controller;
$class = new Controller\Controller;

or

$class = new \Controller\Controller;

or

use Controller\Controller;
$class = new Controller;

The idea is, that the moment you try to access a class with its relative name it tries to map the "first part" against any alias defined using use (remeber use MyClass is the same as use MyClass as MyClass. The thing after as is the alias).

namespace MyNamespace\MyPackage\SomeComponent\And\So\On {
  class MyClass {}
}
namespace Another {
  use MyNamespace\MyPackage\SomeComponent; // as SomeComponent
  $class =              new SomeComponent\An\So\On\MyClass;
}

As you can see PHP finds SomeComponent as the first part and maps it against the SomeComponent-alias the line above.

You can read more about it in the manual about namespaces.

1 Its called "Full-qualified classname", if you name a class with its complete name.

Comments

6

When you put a class Controller in the namespace Controller, then you have to reference it that way:

$controller = new Controller\Controller();

\Controller would be a class in the global (default) namespace, i.e. as if you used no namespace at all.

6 Comments

dont think you need to do that because of the use Controller; statement
@Cassy yeah that is why I used use Controller; so hopefully I wouldn't have to do that uglier method
@Casey I tried it anyway just to see what would happen and it changed the error to Fatal error: Class 'Controller\Registry'
This is because you are refering to Registry in the global namespace and not in the namespace where it is used. Also your class is actually called Library\Registry\Registry
@Dan, changing $this->registry = new Registry; to new \Library\Registry\Registry did in fact get rid of the errors. There has to be a way to do what I am trying to do though, do you know of a way? The whol point of use is to avoid this
|
3

Strangely I have found that in my example code from the Question above, if I change all the Namespace's that are defined to something like MyLibrary so it would be like this code below...

E:\Library\Registry.class.php File

<?php
namespace MyLibrary
{
    class Registry
    {
        function __construct()
        {
            echo 'Registry.class.php Constructor was ran';
        }
    }
}
?>

Then when I use use MyLibrary\Registry; in another file, I am able to access it how I had planned...

$this->registry = new Registry;

The reason this is very strange to me is this now makes a class name appear to be a Namespace as well. So I would not need to set a Namespace to 'MyLibrary\Library' to access the Registry instead I would do it like I showed in this answer to be able to access it with just calling the name of the class.

I hope this makes sense and helps someone else. I will not accept this as the answer as I am hoping someone with more know-how will come in and post a better Answer with explanation

Comments

1

try

<?php
use \Library\Registry;

namespace Controller;
class Controller
{
    public $registry;
    function __construct()
    {
        include('E:\Library\Registry.class.php');
        $this->registry = new Registry;
    }
    function show()
    {
        echo $this->registry;
        echo '<br>Registry was ran inside testcontroller.php<br>';
    }
}
?>

and

<?php
namespace Library\Registry;
class Registry
{
    function __construct()
    {
        return 'Registry.class.php Constructor was ran';
    }
}
?>

Comments

1

First off, I believe you are using composer or composer is initialised in your project. If so, check composer.json file for your autoload, psr-4 definition. For example, if the root of your application is "App", then in your psr-4, you should be doing "autoload": { "psr-4": { "App\\": "./" } }, Furthermore, remember to clear composer cache and dump-autoload from the terminal as follows:

composer clear-cache
composer dump-autoload

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.