namespace user;
use robot\r;
$namespace = 'r\someClass';
$class = new $namespace(); // does not work
$namespace = '\robot\r\someClass';
$class = new $namespace(); // does work
Why doesn't this work as expected?
The reason I am using a variable is b/c "someClass" isn't known ahead of time.
So the code looks like this:
if ( $class == 'someClass' )
{
$namespace = 'r\someClass';
}
elseif ( $class == 'someOtherClass' )
{
$namespace = 'r\someOtherClass';
}
$class = new $namespace();
This is easy to work around, but I don't understand why:
$class = new r\someClass() will work
and $class = new $namespace() will not work.
Updated:
When you use dynamic class name, you have to include the namespace name.
So the below will work:
namespace user;
use robot\r; // use is not necessary when you use dynamic class name.
$namespace = 'robot\r\someClass'; // for a dynamic class name, namespace is required.
$class = new $namespace();
Note the leading slash is not necessary, because there is no difference between a qualified and a fully qualified Name inside a dynamic class name, function name, or constant name.
Check the document here.
Should be able to use #xdazz answer, but you can also alias the namespace. The reason it is failing is you have to full quality namespace path.
use robot\r as r;
$classname = 'r\someClass';
without the
as r
part you have to fully qualify the path later.
I stumbled upon the same issue a few minutes ago - should've looked in here ealier :)
unfortunately i can't comment yet so here's a tiny hint that you can also use the __NAMESPACE__ constant instead of retyping the whole qualified namespace when your class is relative to the current namespace...
In my case i have a small factory method:
public function getService($name)
{
$className = __NAMESPACE__ . '\Service\\' . $name;
return new $className();
}
Related
So I created these two classes
//Quarter.php
namespace Resources;
class Quarter {
...
}
//Epoch.php
namespace Resources;
class Epoch {
public static function initFromType($value, $type) {
$class = "Quarter";
return new $class($value, $type);
}
}
Now this is a a very simplified version of both, but is enough to illustrate my question. The classes as they are shown here will not work as it will not find the Quarter class. To make it work I could change the $class variable to
$class = "\Resources\Quarter";
So my question is: Why do I need to use the namespace here when both classes are already members of the same namespace. The namespace is only needed when I put the classname in a variable so doing:
public static function initFromType($value, $type) {
return new Quarter($value, $type);
}
will work without problems. Why is this and is there any potential traps here I need to avoid?
Because strings can be passed around from one namespace to another. That makes name resolution ambiguous at best and easily introduces weird problems.
namespace Foo;
$class = 'Baz';
namespace Bar;
new $class; // what class will be instantiated?
A literal in a certain namespace does not have this problem:
namespace Foo;
new Baz; // can't be moved, it's unequivocally \Foo\Baz
Therefore, all "string class names" are always absolute and need to be written as FQN:
$class = 'Foo\Baz';
(Note: no leading \.)
You can use this as shorthand, sort of equivalent to a self-referential self in classes:
$class = __NAMESPACE__ . '\Baz';
(Symfony framework is used) I am trying to initialize object like this
$token = new $provider; where $provider is Dropbox and I am getting this exception
Attempted to load class "Dropbox" from the global namespace.
Did you forget a "use" statement?
But if I change the code to $token = new Dropbox; then it works, where is the problem ?
Even if you have declared the Dropbox class in a use statement, when creating a class in that method, you need to have the FQDN of the class as the string.
Example;
$provider = '\MyBundle\Classes\Provider\Dropbox';
$token = new $provider;
Worth reading http://php.net/manual/en/language.namespaces.dynamic.php
[...] there is no difference between a qualified and a fully qualified
Name inside a dynamic class name, function name, or constant name [...]
When you reference a classname by a string, you need to define it with fully-qualified namespace.
Prepend it with namespace where the class belong,
$class = 'Provider\Namespace\' . $provider;
$class = new $class;
Don't also forget to escape the backslash if you prefer double quote
$class = "Provider\\Namespace\\$provider";
$class = new $class;
If it does exists within the same namespace, simply prepend php predefined constant
$class = __NAMESPACE__ . '\' . $provider;
I'm trying to update my project with namespaces.
Before using namespaces I could easily call a class via a variable like so:
<?php
$className = "Item";
$myClass = new $className();
?>
Now, when using namespaces (with use) I'd expect this to work:
(not working allways meens: 'Can't find class' or smth like this)
<?php
namespace myProject
use myProject\Models
$className = "Item";
$myClass = new $className(); // this class has the namespace myProject\Models
// this doesn't work! (can't find class)
$myClass = new Models\$className();
// nope, doesn't work either
$myClass = new myProject\Models\$className();
// nope
?>
but calling the same class directly - without a variable - IS working
$myClass = new Item();
What I have to do, to make it work is:
<?php
namespace myProject;
use myProject\Models; // unnessecary now
$className = "\\" . __NAMESPACE__ . "\\Models\\" . "Item";
$myClass = new $className();
?>
My question now is:
If I want to call a class via a variable, do I really have to include the whole namespace as a fully qualified name?
EDIT:
I found myself an answer here:
Dynamic namespaced class with alias
I'll keep that question anyway, because I could not find the right answer in first place.
I need to instance different object into a same method.
I have found soluce here:
Creating PHP class instance with a string
But when I use that on Controller of Symfony2 I have this error :
Attempted to load class "PhotoType" from the global namespace.
Did you forget a "use" statement?
I didn't understand because I have add all of my "use"
namespace DIVE\FileUploaderBundle\Controller;
use DIVE\FileUploaderBundle\Entity\Photo;
use DIVE\FileUploaderBundle\Form\PhotoType;
...
class DefaultController extends Controller {
public function listFileAction($fileType) {
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository("FDMFileUploaderBundle:".$fileType);
$files = $repository->findAll();
$forms = array();
foreach ($files as $file) {
$class = $fileType."Type";
array_push($forms, $this->get('form.factory')->create(new $class(), $file));
}
$formViews = array();
foreach ($forms as $form) {
array_push($formViews, $form->createView());
}
return $this->render("FDMFileUploaderBundle:Default:list".$fileType.".html.twig", array(
"forms" => $formViews
)
);
}
}
Sorry for my English, I am learning it.
Try this:
foreach ($files as $file) {
$class = 'DIVE\FileUploaderBundle\Form\' . $fileType . 'Type';
// ...
}
Actually you could find the answer in the last comment of the accepted answer to the very question you linked to:
Please note the when using namespaces, you must supply the full path: $className = '\Foo\Bar\MyClass'; $instance = new $className(); – Giel Berkers Dec 16 '14 at 8:23
Basically, in order to instantiate a class from a string, you must use the fully qualified name of the class - including the namespace. Check the page Namespaces and dynamic language features from PHP Manual for a quick explanation and examples.
According to http://php.net/manual/en/language.namespaces.dynamic.php
One must use the fully qualified name (class name with namespace prefix). Note that because there is no difference between a qualified and a fully qualified Name inside a dynamic class name, function name, or constant name, the leading backslash is not necessary.
So I created these two classes
//Quarter.php
namespace Resources;
class Quarter {
...
}
//Epoch.php
namespace Resources;
class Epoch {
public static function initFromType($value, $type) {
$class = "Quarter";
return new $class($value, $type);
}
}
Now this is a a very simplified version of both, but is enough to illustrate my question. The classes as they are shown here will not work as it will not find the Quarter class. To make it work I could change the $class variable to
$class = "\Resources\Quarter";
So my question is: Why do I need to use the namespace here when both classes are already members of the same namespace. The namespace is only needed when I put the classname in a variable so doing:
public static function initFromType($value, $type) {
return new Quarter($value, $type);
}
will work without problems. Why is this and is there any potential traps here I need to avoid?
Because strings can be passed around from one namespace to another. That makes name resolution ambiguous at best and easily introduces weird problems.
namespace Foo;
$class = 'Baz';
namespace Bar;
new $class; // what class will be instantiated?
A literal in a certain namespace does not have this problem:
namespace Foo;
new Baz; // can't be moved, it's unequivocally \Foo\Baz
Therefore, all "string class names" are always absolute and need to be written as FQN:
$class = 'Foo\Baz';
(Note: no leading \.)
You can use this as shorthand, sort of equivalent to a self-referential self in classes:
$class = __NAMESPACE__ . '\Baz';