Is there any way to get any sort of error, be it exceptions, error codes or logging, for when the aliasee introduced by use does not exist?
For example, I tried this one (i.e. using all error signalling I know of):
<?php
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(E_ALL);
use \Foobar as Frob; // \Foobar is actually unknown
print("still here\n");
Together with this line of command in Bash:
display_errors=on php love.php
and get:
still here
as the sole output. I looked into php_errors.log, but nothing is there.
PHP designers, in their much valued sanity, surely have thought of something?
I understand use is just an alias for alias in the world of PHP, yet I don't see why there should not be errors for fully qualified referees.
use statements as such don't really do anything much. All they do is alias a namespaced name to another name of your choice, henceforth allowing you to refer to that shortened alias instead of the full name. That's it. Nothing more happens. The class/function/file isn't actually being loaded at this point nor any other sort of validation is being done. This is because there are many ways to load the actual class that alias refers to, and you may want to do this after the fact later on. Most likely using an autoloader, which will attempt to load the class when it's first actually used.
So: no, there's no way besides trying to use the class.
$frob = new Frob; // Fatal error: class Foobar not found
PHP does not report any error because there is no error in your code.
The use declaration says that Frob is just another name for \Foobar. It is just a declaration, PHP does not try to load \Foobar or check if it exists at that point.
As long as you don't use either Frob or \Foobar in the code, that use declaration has no effect.
But if you try to use it:
$frob = new Frob();
and \Foobar is not a class then be sure PHP will trigger a fatal error and stop the execution of the script.
The use declaration works like the symbolic links in the file system. You can create the file a that is a symbolic link to b and as long as you don't try to read from a (or b), nobody cares if b exists or not.
Related
This is my project path configuration
./create.php
/Install/Install.php
create.php
<?php
use Install\Install;
echo "Starting";
$install = new Install();
This gives me the error
PHP Fatal error: Uncaught Error: Class 'Install\Install' not found in /project/create.php:6
Install.php
<?php
namespace Install;
class Install
{
//whatever
}
Can someone explain me what is happening there ?
Obviously I guess that using a require_once line with my filename would probably fix the issue...but I thought using namespace and use import could prevent me from doing that like we do in classic framework like symfony / magento ?
I've seen some post speaking about autoloading, but i'm a little bit lost. Haven't been able to find a clear explanation on the other stack topic neither.
PHP compiles code one file at a time. It doesn't have any native concept of a "project" or a "full program".
There are three concepts involved here, which complement rather than replacing each other:
Namespaces are just a way of naming things. They allow you to have two classes called Install and still tell the difference between them. The use statement just tells the compiler (within one file) which of those classes you want when you write Install. The PHP manual has a chapter on namespaces which goes into more detail on all of this.
Require and include are the only mechanisms that allow code in one file to reference code in another. At some point, you need to tell the compiler to load "Install.php".
Autoloading is a way for PHP to ask your code which file it should load, when you mention a class it hasn't seen the definition for yet. The first time a class name is encountered, any function registered with spl_autoload_register will be called with that class name, and then has a chance to run include/require to load the definition. There is a fairly brief overview of autoloading in the PHP manual.
So, in your example:
use Install\Install; just means "when I write Install, I really mean Install\Install"
new Install() is translated by the compiler to new Install\Install()
the class Install\Install hasn't been defined; if an autoload function has been registered, it will be called, with the string "Install\Install" as input
that autoload function can then look at that class name, and run require_once __DIR__ . '/some/path/Install.php';
You can write the autoload function yourself, or you can use an "off-the-shelf" implementation where you just have to configure the directory where your classes are, and then follow a convention for how to name them.
If you want to Use class from another file, you must include or require the file.
Use require('Install.php'); before use Install\Install;.
If you are planning to do a big project I would recommend to use PHP frameworks rather than coding from scratch.
This has come up a bazillion times, I know, but the expected solutions - ! function_exists() and require_once() - are not working. The question is (and I have done a lot of searching) is there any way to determine at a given point of execution if a function is declared but not exists?
That almost makes no sense typing it out, but that is what is happening. Details:
Here is what we have and where the fatal is thrown:
if (! function_exists('some_function')) {
require_once('file-containing-the-function.php');
}
Fatal error: cannot redeclare some_function, previously declared in file-containing-the-function.php on line XX . . . .
You would think the combination of function_exists() and require_once() (or include_once, tried that as well) would prevent this issue, but in this environment it does not.
The most insightful tidbit I found was in this comment :
A PHP function might not exist, but still declared.
Hence my question, which there doesn't appear to be a good answer for (other than rebuilding the entire system correctly, which is Not Going to Happen Any Time Soon.)
This is in a huge legacy system with global variables and functions everywhere. There are no namespaces and very few classes, plenty of places for things to go wrong. I know the issue lies somewhere in that problem - file-containing-the-function.php is included in an include of an include and so on, many layers deep (a stack trace doesn't even show it.). Even so, by all description, definition, and multitudes of responses on S.O. the wrappers should work.
At the point of this code it does not come up in get_defined_functions(). Everything is global and top level, there are no functions inside functions or any of the usual suspects, like an overlooked extra include. require_once() is also applied in the other files where file-containing-the-function.php is included. get_included_files() files not show that file file-containing-the-function.php has even been included at the point of this code's execution.
The file that this code lives in is an include itself and inherits some_function() from another include somewhere else. I cannot move the include of this file or this code up the call stack far enough to ensure this is executed first (and would break a lot of other things if I did.) This code has to exist where it does, as this particular file may be included without including file-containing-the-function.php. For example, this may be among 20 or 30 other includes in practical use for a web page output, but when you unit test it, only this file is included.
This is such a simple and basic thing, any way to determine if a global function is declared?
I'm not really sure what's going on, because the error message implies that the file is being required multiple times, even though you used require_once. The whole point of the _once versions of require and include is to prevent redefinitions.
Instead of putting the if statement around require_once, put it in file-containing-the-function.php, and then use require_once unconditionally.
if (!function_exists('some_function')) {
function some_function(...) {
...
}
}
For someone who is still interested to know, in the comment you referred by fritzmg,
function_exists still won't be benefiting you, since you can't declare the function again by loading file in false case.
Simply
if you use "include_once" or "require_once" anywhere in project you don't need function_exists. But if you still get error, then it is because of any of two cases.
1. You declared function in more than one files in the project.
2. Some where else in project you are using require or include two times for including the same file. Or doing once by require and once by include.
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.
Is there a way to check if class exists within a file without including/requiring the class?
Something like: class_in_file($file);
As I already mentioned, I know this can be done with requiring/including the class and then looking up class_exists($class);, but any other ways?
$tokens = token_get_all(file_get_contents('foo.php'));
Then go through the tokens to see if you can spot a certain T_CLASS entry.
http://www.php.net/manual/en/function.token-get-all.php
http://www.php.net/manual/en/tokens.php
A php file is a text file, you can open it and parse it in order to find a
class declaration.
It isn't a simple process, but a good parser should make the task trivial.
You have to strike out commented lines, strings containing a class declaration can trigger a false-positive, heredocs tend to make things more complex. Evals should be taken in account also.
if you have access to a command line php interpreter, then you can have a look at -w switch that strips comments and whitespaces for you doing a good half of yor work for you.
The short answer is no. There are only workarounds. For example, you could parse the file yourself (perhaps using token_get_all), or perhaps mark the file somehow with a comment at the top like
<?php
/** #has_class(CLASSNAME)
*/
and read the first few lines looking for this with a preg_match.
PHP will only know which classes exist if it has loaded (parsed) the files they're defined in (assuming they're not built in). If you have a clearly defined structure (maybe you're using autoloading), you could possibly check that a class exists simply by checking that the file that defines it exists. e.g. if (file_exists('<path to app>/lib/Myapp/Util/Http.php')) could be used as a check that the Myapp_Util_Http class exists in your app directories. It's no guarantee the class does actually exist in that file though. For that you either have to include/require it, read it and parse it, or use autoloading and try using it.
Does anyone have a clue about this? PHP 5.2.13. Results not wholly consistent i.e. could get a good result with a page at one time, then get an error at another.
The error is fatal - class does not have method.
But the following are true:
The class is defined in only one place and has the relevant method in the code.
At the point where failure occurs: reflection shows that the method exists.
At the point where failure occurs: method_exists says the method does not exist.
Previous calls (they're all static - not my choice) earlier in the code worked.
May be it's related: http://bugs.php.net/bug.php?id=51425
But I think here we have some cache-related problem. Do you have some cache enabled? Like APC or any other accelerators?
Be sure that the file containing the method is included. If the method is in a class, make sure the class instance is created and the method is called through the class.
Maybe you are missing the class instance?