"Curiosity is the very basis of education and if you tell me that curiosity killed the cat, I say only the cat died nobly." - Arnold Edinborough

I love PHP, I really do… just, sometimes you fall into these situations where you just can’t help bang your head against the table until even the table starts bleeding.

I’m currently working on a blog series about intelligent caching with PHP. During the preparation for this I had to create a framework which could demonstrate the caching concepts I was going to be discussing, and what better than using namespaces for it. Namespaces makes auto loading easy as pie, they give you an incredible freedom in class naming due to the extra encapsulation layer and in general they’re just brilliant. Except for this.

$controller = '\Evil\Controller\News';
$data = $controller::dataKeyInvalidates($invalidate);

It simply wouldn’t work. I was certain it worked fine without namespaces so for kicks I tried this:

$data = \Evil\Controller\News::dataKeyInvalidates($invalidate);

And it ran without problems. Fun. What eventually let me figure out what was going on was by echoing the variable passed to my auto loader. When I used a variable to reference the class name the auto loader was passed “\Evil\Controller\News” when I didn’t the auto loader was passed “Evil\Controller\News”. Obviously some magic goes on inside PHP that translates \Evil\Controller\News into “Evil\Controller\News”. Setting $controller to ‘Evil\Controller\News’ made it work perfectly fine.

So to recap this:

// Does not work.
$controller = '\Evil\Controller\News';
$data = $controller::dataKeyInvalidates($invalidate); 

// Works.
$controller = 'Evil\Controller\News';
$data = $controller::dataKeyInvalidates($invalidate); 

// Works.
$data = \Evil\Controller\News::dataKeyInvalidates($invalidate); 

// Does not work.
$data = Evil\Controller\News::dataKeyInvalidates($invalidate);
  • Albert

    Posted: September 20, 2010


    Hi great article!

    But it seems to work for me:


    namespace Evil\Controller {

    class News {
    function dataKeyInvalidates($foo) {
    var_dump( 'WORKS', $foo);
    }
    }
    }

    namespace {

    // Does not work.
    $controller = '\Evil\Controller\News';
    $data = $controller::dataKeyInvalidates(1);

    // Works.
    $controller = 'Evil\Controller\News';
    $data = $controller::dataKeyInvalidates(2);

    // Works.
    $data = \Evil\Controller\News::dataKeyInvalidates(3);

    // Does not work.
    $data = Evil\Controller\News::dataKeyInvalidates(4);
    }


    output:

    string(5) "WORKS"
    int(1)
    string(5) "WORKS"
    int(2)
    string(5) "WORKS"
    int(3)
    string(5) "WORKS"
    int(4)


    PHP 5.3.2-1ubuntu4.2 with Suhosin-Patch (cli) (built: May 13 2010 20:03:45)

    Which version do you use? Reply


    • fjordvald

      Posted: September 20, 2010


      This was tested with PHP 5.3.3.

      The situation is not exactly the same, though. If you define your second namespace as anything other than the root you will get failed calls. But that is to be expected.

      The problem here was in the data passed to the autoloader. So to test this you'll need multiple files.

      The interesting part in the following code is the data passed to the auto loader. Also note that you can only test one action at a time as once the file is loaded the remaining calls won't call the autoloader.

      File 1:


      namespace Evil\Controller {

      class News {
      function dataKeyInvalidates($foo) {
      // Nothing required
      }
      }
      }


      File 2

      namespace Evil\Core {
      class CacheController {
      public function __construct {
      spl_autoload_register(array($this, 'autoLoadController'));

      // Does not work.
      $controller = '\Evil\Controller\News';
      $data = $controller::dataKeyInvalidates(1);

      // Works.
      $controller = 'Evil\Controller\News';
      $data = $controller::dataKeyInvalidates(2);

      // Works.
      $data = \Evil\Controller\News::dataKeyInvalidates(3);

      // Does not work.
      $data = Evil\Controller\News::dataKeyInvalidates(4);
      }

      public function autoLoadController($class) {
      var_dump($class);
      }
      }
      }
      Reply


  • Gregory Kornblum

    Posted: December 12, 2010


    Sorry for the delayed response, just following links from the NginX wiki...

    Even now PHP is an infant in the world of OOP let alone the encapsulation concepts born from its ideology. Although the authors who write their parts in C++ know this concept well when your trying to add it to what started out as nothing more then a template language there are gonna be things like this.

    Languages or their extensions in C's case need to decide from the get go what they are going to be or changes to that later on will be a rough undertaking and this is one side effect.

    Examples are abound. Ruby/Python, both, Objective-C, just OOP, no namespaces, C++/Java/C#, just OOP, namespaces. PHP, uhh... template... uhh.. no wait, functional, uhhh... no, scap that, OOP, uhhh.... wait, OOP & namespaces.

    See? ;) Reply


  • Juan Manuel

    Posted: February 8, 2011


    It isn't an escape problem ?


    $ php -r "var_dump('\Evil\Namespace');"
    ilNamespace');"string(15) "\Evil\Namespace"
    $ php -r "var_dump('\\Evil\\Namespace');"
    string(15) "\Evil\Namespace"
    Reply


    • fjordvald

      Posted: February 10, 2011


      I somehow doubt it. The issue is that when you use namespaces in their vanilla version you must use a \ first to specify that you want to start from the root namespace and not relatively to the current namespace. When you use namespaces through a variable you have to specify them in the style that'd normally be used for relative namespace paths.

      Even if it was an escaping problem then that does not explain why, what would normally be a relative namespace path (no prefixed \), would be treated as an absolute namespace path. (prefixed \) Reply


      • Juan Manuel

        Posted: February 17, 2011


        Somehow I have different outputs with PHP 5.2 and 5.3.5:


        $ php -v
        PHP 5.3.5 with Suhosin-Patch (cli) (built: Jan 6 2011 07:17:24)
        Copyright (c) 1997-2009 The PHP Group
        Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
        with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans
        $ php -r "var_dump('\Evil\Namespace');"
        ilNamespace');"string(15) "\Evil\Namespace"



        $ php -v
        PHP 5.3.3-1ubuntu9.3 with Suhosin-Patch (cli) (built: Jan 12 2011 16:07:38)
        Copyright (c) 1997-2009 The PHP Group
        Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
        with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans
        $ php -r "var_dump('\Evil\Namespace');"
        string(15) "\Evil\Namespace"
        Reply


        • fjordvald

          Posted: February 17, 2011


          It doesn't make a lot of sense to just var_dump a string, at that point there's nothing related to namespaces about it. It's only interesting when used in combination with auto loaded class and namespaces. Reply



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>