Instantiate a PHP stdClass in my namespace – fatal error - php

I want to write a small add on for an existing CMS. To do so, I need to extend a class from that CMS' code.
My code will be written inside its own namespace, while the CMS' code does not use namespacing, which basically means it exists inside the global namespace.
Inside my code, I create a new stdClass:
$var = new stdClass();
With that code is place, it always produces a fatal error:
Fatal error: Class 'MyNamespace\something\StdClass' not found in /some/rather/long/path/to/class.php on line 123
Creating the stdClass like this solves that problem:
$var = new \stdClass();
Since I am still pretty new to namespaces, I am not exactly sure what the problem here is?
My guess is that in the first example, the stdClass would be created in the namespace of my class. This actually means the constructor of a class called stdClass existing in my namespace would be called, but since that class does not exist, an error is thrown.
In the second example, I signalize that I want to instantiate the class called stdClass from the global namespace, which somehow suddenly makes sense.
If anyone could elaborate what is happening here I would be very happy.

You appear to understand the concept behind namespaces, and you are headed in the right direction on your analysis of what is happening.
When you are working inside of a namespace you are able to refer to names as unqualified, qualified, and fully qualified.
When you make a namespace you are telling PHP to organize (and resolve) the names of your classes, function, methods, etc. away from the same scope where the built-in PHP code lives along with any other code behind its own namespace. It is away to organize your code and avoid naming collisions among libraries and built-in PHP functions.
Here is a brief on how names get resolved:
If you are trying to resolve a name within the same namespace you can use the unqualified name. So for class \Foo\Bar\Baz you can use new Baz(); as long as you are in namespace \Foo\Bar.
If you are trying to resolve a name that is lower in the same parent namespace you can use the qualified name. So for class \Foo\Bar\Baz you would need to use new Bar\Baz(); if you were in namespace \Foo.
If you are trying to resolve a name that is not in your namespace or is in the global namespace (built-in PHP stuff) then you must use the fully qualified name. If you are in namespace \Foo\Bar and you want to make use of something like the mysqli class you would need to call it by its fully qualified name. e.g. new \mysqli() Your question above is a perfect example that illustrates this. Likewise, if you need to access a class in a totally different namespace you would also need the fully qualified name: new \Third\Party\AppClass();
So to summarize, you are right, the built-in stdClass does not exist in your namespace, therefore you need to access it by the fully qualified name. The reason you must do thing this way had to do with conforming to the rules PHP uses when resolving names.
If you ever need to find out what namespace you are in it will be in the __NAMESPACE__ constant.
In case you haven't already read it, here is the documentation on name resolution in PHP: http://php.net/manual/en/language.namespaces.rules.php

The code is evaluated in your namespace and stdClass doesn't exist there. You are effectively answering your own question with your guess.

Your guess is correct. Look at the comments in "class references" section of Example #1 on this page.
http://php.net/manual/en/language.namespaces.rules.php

Related

Autoloading package that contains Class of same name as imported class

I have a project that includes a PHP file that defines a class named Response and I'm auto-loading Guzzle via composer (which also defines it's own Response class)
The question is do I run the risk that PHP might get confused as to which Response class it should use? If I use Response by itself I don't run the risk that it will somehow fetch the Guzzle class unless I do a use statement right?
I think it's fine unless I do the use statement but I just wanna be sure.
You don't have any risk of conflicts, that's why PHP Namespaces exist!
Although the short name of both classes are the same, their FQCN (Fully Qualified Class Name) are different, so there's no chance of getting confused.
Guzzle's Response class is:
\Guzzle\Http\Message\Response
Your class would be something like:
\MyApp\Response
(or just \Response if you didn't set a namespace for it, which is a very bad practise!)
You can use either of them in your classes, or even both, as long as you set an alias for one of them:
use \MyApp\Response;
use \Guzzle\Http\Message\Response as GuzzleResponse;
// ...
$myResponse = new Response();
$guzzleResponse = new GuzzleResponse();
As long as the classes got individual namespaces.
Composer (and its autolaoder) will resolve the namespace with the classname.
So if you use your own class ("Class1") and the foreign class ("Class2") with the same classname ("Classname") with different namespaces e.g.
namespace \Me\MyPackage\Classname
namespace \Guzzle\Classname
you will be fine. If you wanna create an instance of one of the classes just type the full qualified namespace e.g.
$var1 = new \Me\MyPackage\Classname();

When is it possible to create two controllers with the same name in Symfony2?

I start getting below error after defining a second controller class PostController in different bundle of the same project with the same vendor name.
Fatal error: Cannot redeclare class
Amce\Bundle\CrudzBundle\Controller\PostController in
C:\xampp\htdocs\community\src\Amce\CrudzBundle\Controller\PostController.php
on line 350
I understand that this error means that I have the same name for two classes (OOP). But why even if I have a different bundle with different vendor part, I keep having this error? Does it mean that Synfony2 disallows having two controller classes with the same name in all situations?
Your expert explanations are always appreciated.
I assume the namespace of the culprit class is:
namespace Amce\Bundle\CrudzBundle\Controller
However the file path is:
C:\xampp\htdocs\community\src\Amce\CrudzBundle\Controller\PostController.php
If you copy/pasted the original class, you may have forgotten to change the namespace.
The autoloader would check the this directory for a class that doesn't exist (because of said namespace), however before that, it will have discovered the exact same namespace/class previously.
In PHP 5.3, the namespace is incorporated into the class name. It's important to remember there is no distinction between them, because they are combined at compile time.
Despite the fact you can call __NAMESPACE__ to get the current namespace, in reality this is not performing a dynamic introspection of the code, but instead the magic constant was converted to a constant string at compile time.
The same is true with classes, the namespace becomes part of the class name, and that is how the class is indexed in the internal reference table.
So be mindful of namespaces.

Should "use" statement generally reference a [fully qualified] class or a namespace?

There are lots of articles that describe how to use namespaces in PHP-5.3+ I am particularly interested in the conventions in the use statement.
What most articles dot not point out, is that use can reference a namespace or a class. So to reference my class in PSR-0 location Foobar/Helper/Helper.php I can either do this:
use \Foobar\Helper; // This is a namespace
class Whatever {
...
Helper\Helper::MyHelperMethod();
or this:
use \Foobar\Helper\Helper; // This is a class
class Whatever {
...
Helper::MyHelperMethod();
No packages I have seen document which they are using on each use statement, and that can often lead to guesswork.
So, is it bad practice to use one approach or the other? Or perhaps to mix the concepts? Or is it perhaps just one of those things people rarely document?
Or maybe I am just misunderstanding the whole issue?
If you have a namespace \Foobar\Helper, then
use \Foobar\Helper;
allows you to access all classes from the \Foobar\Helper namespace with Helper as a namespace qualifier. The line
use \Foobar\Helper\Helper;
gives you more control over what classes you want to access without the namespace qualifier. On the other hand, it is quite tedious to keep the use declarations in sync with the code during development. On the third hand, it servers as a documentation about what dependencies exist in the file.
To distinguish whether a use statement refers to a namespace or a class, an IDE such as Eclipse PDT helps.
The point of use is to reduce repeatedly typing the same fully qualified class name. It allows you to produce shorter, more readable code. It depends on your situation which is the most readable way to write your code. If you just need one class from a namespace, you can alias it directly. If you need a lot of classes from one namespace, it may make the most sense to alias only up to the namespace. If several classes from separate namespaces are similarly named, it can make code clearer if you only alias up to the namespace. It's entirely up to you and the situation.

PHP: What options are there to refactor double used classname?

On a web project there are two classes that have the same name. This was never an issue until now, because the two classes where never used at the same time / in the same script.
Now we require to use both classes in one script, and therefor got ourselves an "Cannot redeclare class" fatal error.
My question is: What options are there to resolve this issue?
The one possible solution would be to rename one of the classes in question, but it is something I would very much like to avoid - one of the classes is part of a third-party software that should not be modified at this level, to remain updateable.
I know there are namespaces - are they a valid option to this problem? I have never used namespaces until now.
Assuming we would put one of the classes into a namespace: Would this resolve the issue? Also, what measures would we need to take to access the now-namespaced class?
Namespaces would surely solve your problem.
For example I got multiple classes named 'core', but because they're all classes of a different namespace it doesn't give any conflict at all.
This does mean you have to go over all your code and refer to the namespaced class with the correct path.
$item = new doubleClass();
would become
$item = new \my_namespace\doubleClass();
Also make sure that your other scripts don't get namespaced otherwise it wouldn't be able to find the non namespaced class anymore.
How Namespace work:
consider we have 2 classes named User in file structure
/Package1/User.php
with content
<?php
namespace Package1;
class user {...}
and
/Package2/User.php
with content
<?php
namespace Package2;
class user {...}
and now for some reason we decide to use both in some class UserManager in:
/Package3/UserManager.php
with content:
<?php
namespace /Package3;
use package1/User as User1;
use package2/User as User2;
class UserManager {
public function __construct(User1 $user1, User2 $user2) {...}
...
}

How does the keyword "use" work in PHP and can I import classes with it?

I have a file with a class Resp. The path is:
C:\xampp\htdocs\One\Classes\Resp.php
And I have an index.php file in this directory:
C:\xampp\htdocs\Two\Http\index.php
In this index.php file I want to instantiate a class Resp.
$a = new Resp();
I know I can use require or include keywords to include the file with a class:
require("One\Classes\Resp.php"); // I've set the include_path correctly already ";C:\xampp\htdocs". It works.
$a = new Resp();
But I want to import classes without using require or include. I'm trying to understand how use keyword works. I tried theses steps but nothing works:
use One\Classes\Resp;
use xampp\htdocs\One\Classes\Resp;
use htdocs\One\Classes\Resp;
use One\Classes;
use htdocs\One\Classes; /* nothing works */
$a = new Resp();
It says:
Fatal error: Class 'One\Classes\Resp' not found in C:\xampp\htdocs\Two\Http\index.php
How does the keyword use work? Can I use it to import classes?
No, you can not import a class with the use keyword. You have to use include/require statement. Even if you use a PHP auto loader, still autoloader will have to use either include or require internally.
The Purpose of use keyword:
Consider a case where you have two classes with the same name; you'll find it strange, but when you are working with a big MVC structure, it happens. So if you have two classes with the same name, put them in different namespaces. Now consider when your auto loader is loading both classes (does by require), and you are about to use object of class. In this case, the compiler will get confused which class object to load among two. To help the compiler make a decision, you can use the use statement so that it can make a decision which one is going to be used on.
Nowadays major frameworks do use include or require via composer and psr
1) composer
2) PSR-4 autoloader
Going through them may help you further.
You can also use an alias to address an exact class. Suppose you've got two classes with the same name, say Mailer with two different namespaces:
namespace SMTP;
class Mailer{}
and
namespace Mailgun;
class Mailer{}
And if you want to use both Mailer classes at the same time then you can use an alias.
use SMTP\Mailer as SMTPMailer;
use Mailgun\Mailer as MailgunMailer;
Later in your code if you want to access those class objects then you can do the following:
$smtp_mailer = new SMTPMailer;
$mailgun_mailer = new MailgunMailer;
It will reference the original class.
Some may get confused that then of there are not Similar class names then there is no use of use keyword. Well, you can use __autoload($class) function which will be called automatically when use statement gets executed with the class to be used as an argument and this can help you to load the class at run-time on the fly as and when needed.
Refer this answer to know more about class autoloader.
use doesn't include anything. It just imports the specified namespace (or class) to the current scope
If you want the classes to be autoloaded - read about autoloading
Don’t overthink what a Namespace is.
Namespace is basically just a Class prefix (like directory in Operating System) to ensure the Class path uniqueness.
Also just to make things clear, the use statement is not doing anything only aliasing your Namespaces so you can use shortcuts or include Classes with the same name but different Namespace in the same file.
E.g:
// You can do this at the top of your Class
use Symfony\Component\Debug\Debug;
if ($_SERVER['APP_DEBUG']) {
// So you can utilize the Debug class it in an elegant way
Debug::enable();
// Instead of this ugly one
// \Symfony\Component\Debug\Debug::enable();
}
If you want to know how PHP Namespaces and autoloading (the old way as well as the new way with Composer) works, you can read the blog post I just wrote on this topic: https://enterprise-level-php.com/2017/12/25/the-magic-behind-autoloading-php-files-using-composer.html
You'll have to include/require the class anyway, otherwise PHP won't know about the namespace.
You don't necessary have to do it in the same file though. You can do it in a bootstrap file for example. (or use an autoloader, but that's not the topic actually)
The issue is most likely you will need to use an auto loader that will take the name of the class (break by '\' in this case) and map it to a directory structure.
You can check out this article on the autoloading functionality of PHP. There are many implementations of this type of functionality in frameworks already.
I've actually implemented one before. Here's a link.
I agree with Green, Symfony needs namespace, so why not use them ?
This is how an example controller class starts:
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class WelcomeController extends Controller { ... }
Can I use it to import classes?
You can't do it like that besides the examples above. You can also use the keyword use inside classes to import traits, like this:
trait Stuff {
private $baz = 'baz';
public function bar() {
return $this->baz;
}
}
class Cls {
use Stuff; // import traits like this
}
$foo = new Cls;
echo $foo->bar(); // spits out 'baz'
The use keyword is for aliasing in PHP and it does not import the classes. This really helps
1) When you have classes with same name in different namespaces
2) Avoid using really long class name over and over again.
Using the keyword "use" is for shortening namespace literals. You can use both with aliasing and without it. Without aliasing you must use last part of full namespace.
<?php
use foo\bar\lastPart;
$obj=new lastPart\AnyClass(); //If there's not the line above, a fatal error will be encountered.
?>
Namespace is use to define the path to a specific file containing a class e.g.
namespace album/className;
class className{
//enter class properties and methods here
}
You can then include this specific class into another php file by using the keyword "use" like this:
use album/className;
class album extends classname {
//enter class properties and methods
}
NOTE: Do not use the path to the file containing the class to be implements, extends of use to instantiate an object but only use the namespace.

Categories