PHP namespace class not found when Use statement is in included fle - php

My problem seems to be around where I am declaring my classes. If I have everything in one .php file, the autoload, the Use declarations and my script that uses those classes within the same file it all works correctly. However, when I have my "Use" statements in a separate required file, I get class not found errors. I eventually want to instantiate class objects in a function, but I can't get past this issue.

My fault - I needed to have the Use statements at the top of every included file. Right there in the documenation, somehow I missed it.

Related

PDO class could not be found in PhpStorm

So, here is some code that I have in my project. Recently started to use PDO methods for connecting to database etc. The problem is that the IDE that I am using (PhpStorm) can't for some reason find any PDO classes. PhpStorm just shows a yellow line underneath the word and says 'Undefined class PDO'.
The weird thing is that if I put a \ before the word PDO, (ie. \PDO) then the class can now be found. I know that from doing some research that you can include it like so use \PDO, however I don't really want to have to do that.
Lastly, wanted to mention that in external libs within PhpStorm that PDO is included which is even more confusing but hopefully you guys would be able to help me out with this.
EDIT - Answer
Ok, after some help I was able to find out why I was getting this issue. At the top of this file I had namespace App\DB; because of this Php was not able to find the PDO class. So, actually putting a \ in front is actually the correct way to do it.
Big thanks to IMSoP, tete0148, Jim Wright.
Just add a backslash before class names because PHP standard classes are located in the root namespace.
\PDO
\PDOException
Or add a use statement at the top of your file.
use \PDO;
use \PDOException;
Note that PHPStorm can automatically import classes by pressing alt+enter while the cursor is over a warning.
I think you have jumped to the conclusion that PHPStorm is telling you the wrong thing, but actually you need to learn how namespaces in PHP work.
Adding a leading backslash to a class name is a way to reference its absolute namespace path.
In this case, the PDO classes are in the root namespace, so they are just \PDO etc; if they were in a namespace called Acme\Widgets, you would write \Acme\Widgets\PDO as the fully-qualified class name.
Fully qualifying the name like this is necessary if the file you are writing is itself declaring code in a particular namespace; that is, if it has the namespace keyword at the top of the file. In that case, the bare name PDO is assumed to be a class in the same namespace you are writing code in. If your file begins namespace ZOulhadj\DB, then new PDO will be expanded as though you'd written new ZOulhadj\DB\PDO.
If this is the case, it is not just PHPStorm which will not be able to find the class - PHP itself will also fail to find the class. PHPStorm is pointing out an error to you so you can fix it before you run the code.
#yann-chabot's (deleted) answer is correct that it will work if you add \ before the classes but he is not clear on why.
In PHP backslashes are used to determine namespaces, and the PDO class is in the root namespace.
If you are in the same namespace as another class, you do not need to specify the namespace when using it. Otherwise, you should specify the namespace.
A simple way of thinking about namespaces are as folders.
For more info see the PHP manual.

Am I using namespaces, autoload, and aliasing correctly?

I've been reading a lot of posts on StackOverflow but I'm not really sure I'm using namespaces, autoloading, and aliasing correctly. This is functioning fine, but I'm not sure I'm properly using these concepts. I've listed some reasons why I think this setup is incorrect at the bottom of the post.
Imagine the following directory structure:
\public_html
- index.php
\Classes
\A
- One.php
\B
- Two.php
One.php is structured like:
<?php
namespace Classes\A;
class A { ....
Two.php is structured like:
<?php
namespace Classes\B;
class B { ....
Then, in index.php I do something like:
<?php
use Classes\A\One as One;
use Classes\B\Two as Two;
spl_autoload_register(function ($className) {
...
});
... ?>
So, a couple things that bug me about this:
If I am doing aliasing (the "use" statements) I still need to list out all of the files. Aren't we trying to avoid doing this by using autoload?
If I want to use internal classes, I need to add a line such as "use \mysqli;" into the class that uses this and do things like "new \mysqli()". Seems kind of messy?
If a class extends a class from another namespace (say Two.php extends One.php for example) then I need to include "use \Classes\A\One as One;" in One.php which seems to be what we want to avoid in the first place
You don't have to reference all of your namespaced classes via a use statement. You can use partial namespaces.
use Classes\A;
new A\One();
So you can see if you had another class in the A namespace it could be instantiated with
new A\Three();
There are many things in the global namespace, you don't need to define them with use. You can just call them \mysqli(). Yes it's a bit unsightly but it allows you to make a function called mysqli in your own code without worrying about collisions with globally namespaced functions.
I'm not sure I follow you on this one. You don't need to do a use in the base class which references itself.
Ultimately it kinda seems like you view use almost like include when they are very different, use, in this context, is a convenience thing so you don't have to type out full namespaces every time.
Your Autoloader also doesn't need to know about your namespaces. The autoloader just tells PHP how to load a class. So if it sees a class come in with the name Classes\A\One you can make it look in the directory /Classes/A for a file called One.php and include it. PHP will make sure that the class is allocated in the proper namespace. The autoloader is just a convenience thing to keep you from having to do includes and requires in each of your PHP files.

PHP/Symfony2, two classes in one file, which should be first?

I've got something that's strange for me. It's in Symfony Controller, but I don't think that matters. In the controller file, next to controller class I created a simple "class" with consts just to keep some things in queries more clear:
class ExportType
{
const EXPORT_WORLDWIDE = 1;
const EXPORT_EU = 2;
}
Of course there's only one namespace at the top. These constants are used in one of the controller's actions.
Every time I use PhpStorm's code autoformatting, that class is moved to the top of the file. OK, I don't mind and PhpStorm doesn't report any error here. But seems like PHP (or Symfony?) doesn't like it, because every time that helper class is on the top, there's a FileLoaderLoadException thrown, saying that class doesn't exist in this namespace.
When it's at the bottom, there's no problem. Is it normal? Should used class be declared after the class that is using it??
The problem probably comes from Composer, you code is simply not PSR-0/4 compliant which is convention Composer is using to autoload your files. You get an error because it can't find the file to load because of that.
It probably works if declared as second because the only place where you are using it is in your Controller. Use your constant somewhere else and it will automatically fail.

PHP Class using namespaces causes problems with my code that doesn't use namespaces. Why?

I'm trying to use a php library called tcpdf-extension. This library uses namespaces and 'use' commmands. The rest of my code does not. I'm pretty new to namespaces and do not understand how to use them.
If I include the library, I get problems with php not being able to find other included/required files. For instance: 'PHP Fatal error: require_once(): Failed opening required <filepath>(include_path='.;C:\php\pear') in <filepath> on line 29'
Another issue is some of my previously working website pages just hang without any error message. If I remove the include for the library, everything goes back to normal.
If I use the library in a separate page from the rest of my code, then there's no problems, but as soon as I include it in any other page, it fails.
Why is this happening and what can I do to fix it?
Update: example of including the library:
require_once ('tcpdf/Extension/Helper.php');
require_once ('tcpdf/Extension/Table/Table.php');
require_once ('tcpdf/Extension/Table/Cell.php');
require_once ('tcpdf/Extension/Table/Row.php');
require_once ('tcpdf/Extension/Table/TableConverter.php');
require_once ('tcpdf\Extension\Attribute\AbstractAttribute.php');
require_once ('tcpdf\Extension\Attribute\BackgroundAttribute.php');
require_once ('tcpdf\Extension\Attribute\BackgroundFormatterOptions.php');
if this is commented out, the problems go away, but I need to use this library.
Here's a section from Table.php:
<?php
namespace Tcpdf\Extension\Table;
class Table{
...
Here's a section from Cell.php:
namespace Tcpdf\Extension\Table;
use Tcpdf\Extension\Attribute\BackgroundAttribute;
class Cell
{
...
My guess is that the use and/or namespace commands have something to do with it because that's the only thing about this library that is different than other libraries I've used without any problems. I've also tried commenting out the use commands and that makes code outside the library work okay, but it makes the library not work. Perhaps after I include this library I need to give another 'use' command to get back to the right namespace for the rest of my code. However, since I've never set a namespace for the code, I don't know what the use command would be.
This is the library in question:
https://github.com/naitsirch/tcpdf-extension
Another detail that might be relevant: Most of my code is procedural style. I often make use of classes, but most of this (very large) code base is not in a class at all. If it were all in classes, I'm sure I could add use statements for each class, but that is not the case.
You should use "use" operator in your file by below way.
use Tcpdf\Extension\Table\Table as TableClass;
after this, "new TableClass();" would instantiate a Tcpdf\Extension\Table\Table Class
For more info, check below link:-
PHP namespaces and "use"
Hope it will help you :-)
The only way I have found to use this library with my existing, non-namespaced, procedural code is to remove all use statements and namespace statements from the library. This library only has 8 files, so this wasn't hard. I'd still like to hear answers from people if they have a better approach, as I'm sure this issue will come up again.

Does PHP's use statement cause extra work when loading classes?

Code Sample 1
use Outline\Drawing;
$var = new Drawing();
Code Sample 2
$var = new Outline\Drawing();
Question:
Does PHP make hardware work harder (look up more files or do more processing) if I use code in sample 1? I am sure something gets done, even if it is at the level of some code that figures out which use line gets matched up with which class. I want to find out exactly what is happenning.
In short:
What does PHP do when working out the connection between the use of the use statement and a class it is supposed to be for?
Are PSR-0/PSR-4 autoloaders affected in the way they work when it comes to these two code samples?
What does PHP do when working out the connection between the use of the use statement and a class it is supposed to be for?
The use statement doesn't actually load the namespace/class into your file. It simply sets up a list of aliases to refer to the classes in that namespace.
When it encounters a class that hasn't yet been declared, it uses that list of aliases to try to fully qualify the class name (prefix replacement). If it can't find an alias for the class, it'll use the namespace of the current scope to qualify the class name.
Only when the class name is fully qualified, that php will try to autoload the class (calling the various autoloaders that might have been defined).
Are PSR-0/PSR-4 autoloaders affected in the way they work when it comes to these two code samples?
No, autoloaders are not affected in the way they work by the difference in your code samples because php will call the autoloaders exactly the same way with exactly the same parameters.

Categories