Reflecting into a class without FQCN - php

Is it possible to reflect into a class without knowing the fully qualified class name?
e.g. instead of this...
(new ReflectionClass(\App\Modules\Companies\Models\Company::class));
...something like this?
(new ReflectionClass('Company'));

Related

Laravel, resolve dependecy by passing class name as string

When I try to resolve a dependecy class like this
app(MyClass::class);
it works perfectly, but what I actually need is to pass the name of the class like a string, something similar to this:
$className = 'MyClass';
app($className::class);
I tried using reflection and every possible way but without success.
You have to pass full namespace of your class such as:
$className = "\\App\\MyClass";
app($className);

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();

Instantiate a PHP stdClass in my namespace – fatal error

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

use all classes in a namespace

I've got a namespace named Foo. There are various classes inside that namespace, let say Bar and Baz.
In some other file, I would like to use the Foo namespace and by that gain access to all of it's classes without prefixing them with the \Foo\ClassName.
What I've tried to do was at the top of the script:
use Foo;
And then simply do something like:
$bar = new Bar;
However, when I try that, I get an error: The use statement with non-compound name 'Foo' has no effect, eventually leading to that I have to specify every class I want to use beforehand. Is there any workaround?
PHP's use keyword doesn't work like C++'s using namespace; in the sense that you can't include an entire namespace. You can alias it or include each class.
If you want to do new Bar;, you'll have to do something like this:
use Foo\Bar;
You'd have to do this for each class you need in the Foo namespace. As far as i know there is no workaround.

Php namespace - repeating Use in each class

I have a lot of classes in multiples subfolders that I load using this autoloader :
spl_autoload_register(function ($class) {
$class = str_replace('\\', DIRECTORY_SEPARATOR, strtolower($class));
if(file_exists(FILES_PATH.'classes/'.$class.'.class.php')){
require_once(FILES_PATH.'classes/'.$class.'.class.php');
}
});
So if i do new Folder\subFolder\Myclass, it works.
The classes in folders are all in a namespace.
All these classes must use the database class, and the problem is here :
When the class is in a namespace and search the database class, it can't find it.
(DB class is in global namespace)
So I try to put "use BDD" (Bdd is the db class) and it still doesn't work, because Bdd is using PDO and so i must do "use bdd, pdo;" in EVERY classes of the project...
I find this stupid. Is this normal ?
Is there a better way to autoload, without using namespaces ?
It's pretty darn simple:
If you're in a namespace like so:
namespace Foo;
all names of all classes are resolved relative to that namespace. Any Bar will mean the class Foo\Bar, not the "global" Bar. If you want to refer in any way, shape or form to a class which is not in the same namespace, say Bar\Baz (class Baz from the namespace Bar), you have two choices:
use a fully qualified name for the class, e.g.:
\Bar\Baz
where the leading \ means the class name shall be resolved from the top namespace, not the current local one, or
if this is getting annoying to do every time, alias it using:
use Bar\Baz;
which is shorthand for
use Bar\Baz as Baz;
which means any time you use "Baz" in this namespace you mean the class Bar\Baz, not Foo\Bar\Baz.
Yes, this applies to each file individually. If you want to refer to PDO in some namespace in some file, you either have to write \PDO to make it resolve to the "global" PDO class or you write use PDO at the top of the file to make a convenience alias. That's how namespaces work.
This applies to all use cases of any class name:
new \PDO
\PDO::staticMethod()
\PDO::CONSTANT
You can explicitly say that BDD is in the global namespace by doing this in your code:
$foo = new \BDD();
Then you should not need to use it.
Moving answer from one of my comments ;)
Using use \Pdo; in BDD class fixed the world :)

Categories