15

I have noticed that when I am using namespacing that loading classes dynamically doesn't work the same as when I'm loading them statically. So, for instance, without the use of namespaces the following are equivalent in their action of instantiating a class called FooBar:

$foobar = new FooBar();

and

$classname = "FooBar";
$foobar = new $classname;

However if when using namespacing I have some code like this:

<?php

namespace Structure\Library;

$foobar = new UserService();
$classname = "UserService";
$barfoo = new $classname;

In this case the UserService class's fully qualified name is Structure\Library\UserService and if I use the fully qualified name it works in both cases but if I use just the shortcut name of 'UserService' it only works when instantiated with the static method. Is there a way to get it to work for both?

P.S. I am using an autoloader for all classes ... but I'm assuming that the problem is happening before the autoloader and is effecting the class string that is passed to the autoloader.

totymedli
  • 29,531
  • 22
  • 131
  • 165
ken
  • 8,763
  • 11
  • 72
  • 133
  • Confused by, "it only works when instantiated with the static method". Where are you using a static `::`? Issue understanding of ['Global Space'](http://www.php.net/manual/en/language.namespaces.global.php)? – ficuscr Mar 22 '13 at 18:27
  • No sorry, i meant the static reference to the class not a "static class". :^) Explicitly, the line that says `$foobar=new UserService();` – ken Mar 22 '13 at 18:37
  • Can you show us the logic of your autoloader? I imagine that within, you use the namespace to calculate the path from which to load the class-file. Is that right? Can't you `echo` your `$class` name from inside the autoloader, to give us a better clue? As Allender has answered, I imagine that what's happening is that the class name being processed includes the namespace in one instantiation, but doesn't include it in another. Essentially, the last line of your code is akin to writing: `$barfoo = new \UserService();`, which fails, because the class is not in the global namespace. – cartbeforehorse Oct 02 '13 at 16:55
  • see also: http://stackoverflow.com/questions/11950517/php-namespace-and-dynamic-classname – cartbeforehorse Oct 02 '13 at 17:03

3 Answers3

13

I think this is a case of reading the documentation. See example 3:

http://php.net/manual/en/language.namespaces.importing.php

Seems to confirm my earlier comment.

<?php
    namespace foo\bar;

    $classStr = "myClass";    
    $nsClass = "\\foo\\bar\\myClass";

    $x = new myClass;    // instantiates foo\bar\myClass, because of declared namespace at top of file
    $y = new $classStr;  // instantiates \myClass, ignoring declared namespace at top of file
    $z = new $nsClass    // instantiates foo\bar\myClass, because it's an absolute reference!
?>
cartbeforehorse
  • 3,045
  • 1
  • 34
  • 49
  • thanks @cartbeforehorse, I'll look at this in a few weeks. Sorry for my lack of response but the question is from 6 months ago and somewhere in the gap I got everything working *well enough*. That said, I still feel I need to ground my understanding. – ken Oct 02 '13 at 18:01
  • @ken I fill these types of questions in for my own future reference, as much as for your info. I wasn't expecting a reply, and imagined that your work would have moved on quite a bit in the intervening 6 months. – cartbeforehorse Oct 02 '13 at 20:28
  • @ken actually, this reply is (technically) almost identical to Allendar. However, I found the format of that reply to be unnecessarily difficult to follow. – cartbeforehorse Oct 02 '13 at 20:32
  • ok it is not possible, anyways that is not good that such a case is not supported by php :-( – Gizzmo Jul 06 '16 at 13:20
  • @Gizzmo I have no idea what you're talking about. – cartbeforehorse Sep 29 '17 at 09:01
  • @cartbeforehorse i would like that php could resolve this line in your example: $y = new $classStr; to its full namespace, perhaps this is clear now;-) – Gizzmo Oct 17 '17 at 07:07
  • nsClass always give error this answer is incorrect ![](https://i.imgur.com/kGNIkmB.png) here is the code and here is the error message saying you cannot do this ![](https://i.imgur.com/DvUsI2D.png) – nikoss Nov 01 '17 at 02:07
  • 1
    @nikoss Just because your code is duff, doesn't mean that mine is! `$c = "\\Carbon\\Carbon"; $x = new $c(); dd ($x);` works just fine. For whatever reason though you can't do `$x = new "\\Carbon\\Carbon"();`. I don't know what the technical reason is, but that's the way the world is. – cartbeforehorse Nov 04 '17 at 15:05
5

This would be the nearest solution I can find:

define('__NSNAME__', __NAMESPACE__.'\\');

$foobar = new UserService();
$classname = __NSNAME__."UserService";
$barfoo = new $classname;

Good luck!

Update 1

This might be good for further reading: http://www.php.net/manual/en/language.namespaces.importing.php

use My\Full\UserService as UserService;

Update 2

This is how far I got now:

namespace Structure\Library\Home;

class UserService {

}

namespace Structure\Library;

use Structure\Library\Home\UserService as UserService;

define('UserService', __NAMESPACE__.'\\Home\\UserService', TRUE);

$foobar = new UserService();
$classname = UserService;
$barfoo = new $classname;

Or this variant for more flexibility:

define('Home', __NAMESPACE__.'\\Home\\', TRUE);

$foobar = new UserService();
$classname = Home.'UserService';
$barfoo = new $classname;

Docs

  • I have tried using the use syntax you suggest but it doesn't seem to help for dynamic class loading (it does for static). – ken Mar 22 '13 at 18:55
  • Did you read the link? If you link the other Class it's location (use) then you should just be able to do: `$obj = new Another;`, in your case `$barfoo = new UserService;`. Off-course my example above (My\Full\) needs to be replaced with your path the Class resides in. –  Mar 22 '13 at 18:57
  • Yes but the `use` operator doesn't appear to be evaluated when dynamically instantiating a class. I use `use` a lot and in this case I've explicitly tried it to no avail. In many ways, this is a case where you wouldn't really want to use `use` though as I'm trying to create a dynamic response and the use statement is static. Anyway, it doesn't work. ;^) – ken Mar 22 '13 at 21:30
  • I'm sorry to hear that ken :(. I will try to do some more research. If I find anything useful; I will add it to this thread. –  Mar 22 '13 at 21:36
  • I've added a second update ken. I hope it helps you (and maybe others) in a brainstorm to get closer to a unified solution. –  Mar 22 '13 at 22:07
0

The following dynamically instantiates $barfoo as a Structure\Library\UserService object:

namespace Structure\Library;

$classname = __NAMESPACE__ . "\\" . "UserService";
$barfoo = new $classname;
Pancho
  • 2,043
  • 24
  • 39