check if class exists within file without requiring/including - php

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.

Related

How to include a specific function using require_once() or include() functions in PHP?

How to include a specific function based on requirement from a php file containing various function definitions.
eg. PHP file functions.php contains 3 functions a(), b() and c()
I have to use require_once('/f/functions.php') in other.php file to use function c.
What could i do to only include the function c in file other.php file using require_once() function and avoid other functions not to be included ?
There is no built in way to do it. Although there are ways to go around it if you do it for the sport.
While this is highly not recommended. Really, just dont do it... here's how:
1) Read the file as text.
2) find the function block and extract it
3) run it through eval.
This will cause any global state set up in the file to not be run. Which you may or may not want.
SuperClosure does something similar I believe to serialize closures, which by default php does not support.
One could leverage the PHP7 abstract syntax tree to also includes related functions. For example, if there are three functions defined - A, B and C. A uses B internally. If you include A, you would want to also include B.
This wont be more performant than just including the whole file, but feel free to prove me wrong with benchmarks.
You might be interested in namespaces. Both classes and functions support it.
You cannot, period. PHP doesn't have any sort of module system. To "include functions", all you can do is execute a source code file (what include will do), which will by the act of executing the code in the file define those additional functions, or anything else that's in the file. You cannot selectively pick only certain parts of the code to run.

How to show namespace-use errors?

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.

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.

Using two class with the same name

I have two PHP apps which have twho class with the same name.
- app1 with a class "Project"
- app2 with a class "Project"
I have to use classes of the first app in the second one, but two class with one name cause an error ("PHP Fatal error: Cannot redeclare class Project ...").
I can't change class names.
I have to use PHP 5.2 (no namespace in PHP 5.2).
Is there a solution ?
May be :
use the class Project
undef this class (kind of "unset Project", is it possible with PHP ?)
include() the 2nd class
use the 2nd class
I don't know if it's possible with PHP (don't find any ressource about this) and I don't know a better way to manage this ...
I had this problem recently, with (embarrassingly) Joomla. I needed to find the versions of two different installations with one script, by loading up their two "version.php" files and then reading the class properties. But, of course, they're both called "JVersion", and it's impossible to require() both version.php files because of it.
After much thought, I realized eval() could take the place of require(). So I just read in the contents of the version.php files and change the names of the classes, then eval() that text, and then I can access both classes with different names. I bet you'd like some code. Here's what I ended up with...
$v15_txt=file_get_contents($old_dir.'/libraries/joomla/version.php');
$v15_txt=preg_replace('/class JVersion/i', 'class JVersion15', $v15_txt);
eval('?>'.$v15_txt);
$jvold=new JVersion15;
$old_version = $jvold->RELEASE.'.'.$jvold->DEV_LEVEL;
$v25_txt=file_get_contents($new_dir.'/libraries/cms/version/version.php');
$v25_txt=preg_replace('/class JVersion/i', 'class JVersion25', $v25_txt);
eval('?>'.$v25_txt);
$jvnew=new JVersion25;
$new_version = $jvnew->RELEASE.'.'.$jvnew->DEV_LEVEL;
Just modify it so it loads the right two files for your needs and renames them as required. Sorry you had to wait over a year for it. :-)
It's hard to believe PHP doesn't have some kind of "undeclare($classname)" function built-in. I couldn't even solve this with namespacing, because that requires changing the original two files. Sometimes ya just gotta think outside the framework.
Stop.
Whatever you are doing is wrong. Backup. Re-evaluate what you are doing and why.
If after that, you still need to do this. Pick an app, and do a find and replace on that class name in the app. If it was well designed, it should be unique and easy to do.
Document the hell out of the fact that you did this in whatever external documentation you are using.

Can I include code into a PHP function or method?

I want to make a kind of "generic" function which gets executed and - depending on what to do - includes it's implementation file via include(). So for example, I might have exactly one function and exactly 20 procedure files for that function. The procedure files may look like do_this_procedure.php, do_that_procedure.php, etc.
As I'm new to PHP I'd like to know from PHP expertes wether this is fine with PHP or not, before I try it and only "believe" it works, and in reality a lot of things go wrong. So what do you think? Currently I think of an include just as an insertion of code right into that place before it gets compiled for execution.
From the include statement documentation:
If the include occurs inside a function within the calling file, then all of the code contained in the called file will behave as though it had been defined inside that function. So, it will follow the variable scope of that function. An exception to this rule are magic constants which are evaluated by the parser before the include occurs.
So yes, you can call include from within a function and use that to define the body of the function. You can even have the file that you include vary with each call to the function. The downside is the include will be evaluated with each call to the function; if the function is called many times, it could seriously impact performance.
Depending on exactly what you're trying to accomplish, an alternative is to follow a functional programming paradigm, which lets you construct functions at runtime. Before PHP 5.3, it's ugly, so I wouldn't recommend it unless you can require at least PHP 5.3.
You may try this too:
PHP Tokenizer.
//from external script:
<?php
var_dump(token_get_all(file_get_contents('myscript.php')));
?>
Including such file will be done on runtime, I believe. Basically, when PHP hits the include/require function, it will eval that file as an independent one.
I'm not sure whether variables passed to the function will be usable in the included file, but global-ing them should work fine.
#outis hit the nail on the head, but an alternative approach would be to create the function as a static method in a class and create an autoloader (via spl_autoload_register, etc.) to include and call the class method at runtime.
Then again, this really wouldn't really buy you anything unless you're already using an OO approach.
outis is correct, however this strikes me as a very ugly and messy way to implement the code. Why not just have different files with different declarations of a function including the function declaration.
Functions should be as short as possible - as a general rule of thumb I will go back and see if it is practical to refactor any function longer than 20 lines. Bearing this in mind, where's the benefit in including the body of a function from a seperate file?
C.

Categories