How can I check a php file for undefined functions? - php

Calling php -l checks the syntax of a php file.
Is there a way to check for undefined functions? I don't need it to work with functions defined at runtime nor with dynamic calls.
Calling the file obviously won't work: I need to check the whole file, not only the branch that gets executed. See the follwing example.
myfile.php:
function imhere () {}
main.php:
require_once 'myfile.php';
if (true) {
imhere();
}
else {
imnhothere(); // I need to get a warning about this
}

Checking for undefined functions is impossible in a dynamic language. Consider that undefined functions can manifest in lots of ways:
undefined();
array_filter('undefined', $array);
$prefix = 'un'; $f = $prefix.'defined'; $f();
This is in addition to the fact that there may be functions that are used and defined conditionally (through includes or otherwise). In the worst case, consider this scenario:
if(time() & 1) {
function foo() {}
}
foo();
Does the above program call an undefined function?

Check the syntax only need to scan the current content of the php file, but check for function defined or not is something different because functions could be defined in the required file.
The simplest way is just to execute the file, and undefined function will give you a PHP Fatal error: Call to undefined function .....
Or you may want this.

Following comment tennis I thought I would wrap up some thoughts into an answer.
It seems like what you might need is some higher-level testing (either integration or web testing). With these you can test complete modules or your whole application and how they hang together. This would help you isolate calls to undefined functions as well as a host of other things by running tests against whole pages or groups of classes with the relevant includes statements. You can PHPunit for integration testing (as well as for unit-) although I'm not sure that would gain you that much at this point.
Better would be to investigate web-testing. There are a number of tools you could use (this is by no means intended to be a complete list):
Selenium which I believe can hook into PHPUnit
SimpleTest, not sure how well maintained this is but I have used it in the past for simple (!) tests
behat, this implements BDD using Gherkin but I understand it can be used to do web-testing (behat with Goutte

Related

Is using the short notation for directly called function safe in PHP7?

Since PHP7 it seems to be possible to directly call anonymous functions like this:
(function () { echo 'Hello!'; })();
I found this by accident in some open source code base. I tried to find any hint on this in the PHP documentation (including changelogs and RFCs). There seems to be none, it seems fully undocumented.
Is it safe to call functions this way or should I use call_user_func(); like in the old days? Is this documented somewhere?
I know of these questions and answers:
IIFE (Immediately Invoked Function Expression) in PHP?
https://stackoverflow.com/a/35044603/1708223
They just say it's supposed to work and how it works. I know this. My question is not about the "how"! It's about whether this is actually an official PHP feature or if it'S merely working "by accident" (because it seems undocumented).
The reason you won't find this documented as a feature in the main manual is because it isn't one, it's just a consequence of other features:
function () { echo 'Hello!'; } creates a Closure object
putting () after a Closure object executes that closure
That's not quite the same as accidental, but I can see why you might think that, because it didn't work in PHP 5.
The reason it changed is that PHP's parser was overhauled in PHP 7.0 to use more consistent rules when parsing variables, as well as introducing an extra stage called an Abstract Syntax Tree. This changed the meaning of some code, but allowed for other cases that logically should have been possible, but were previously hard to implement.
Allowing code that was previously a syntax error is not generally considered a compatibility break, so not every piece of syntax enabled by this change made it into migration guides.
However, removing this functionality - even if not documented - would be a compatibility break, so at the very least you will get some notice that it's going to change, and it would be in a "major version" (9.0, 10.0, etc). Since it's a useful piece of syntax, there's no reason to suppose it will ever stop working, unless there's some even more useful feature that conflicts with it for some reason.
Just to put some thoughts together: (function () { echo 'Hello!'; }) defines a class instance of type Closure. Putting the closure into a variable helps to understand that:
$x = (function () { echo 'Hello!'; });
echo gettype($x);
This prints object, since PHP 5.3. The result of $x(); hasn't changed since PHP 5.3 either. But what has changed is the unified handling of variables - this enables that you don't have to define a variable explicitly, but call the closure directly as if you had put it in a variable first

Zend 2 Imports and Global Namespace

I'm trying to wrap a legacy application in the Zend2 MVC framework. Thanks to the Zend Skeleton Application and code samples (especially https://github.com/maglnet/MaglLegacyApplication), I've solved most of my issues.
The one big issue I haven't been able to solve is illustrated by the following "legacy" file:
<?php
$test = "test";
function echo_test(){
global $test;
echo "test = ";
var_dump($test); # Makes NULL explicit
}
echo_test();
In the Controller for a ZF2 module, I capture the output of the include using an output buffer and stick that into the response object:
...
chdir($filePath) # Fixes relative includes
ob_start();
include $filePathAndName;
$output = ob_get_clean();
$response->setContent($output);
return $response;
... and I get back test = NULL.
I've seen warnings that ZF2 namespaces can create issues for legacy files and done my legwork to try and clarify why. According to the PHP guide, "Without any namespace definition, all class and function definitions are placed into the global space". Indeed, my sample is only slightly more complicated than the one listed below this statement... but it doesn't seem to work.
I also see that "You can set a variable after declaring a namespace, but variables will always exist in the global scope. They are never bound to namespaces.".
I continued to research and have finally discovered that this approach "will import the contents of the include file into the method scope, not the class scope".
Is there any way to process the file outside the method scope?
This is nothing to do with PHP namespaces. If you're including a file from within a ZF controller action, it will execute within that function's variable scope. For your example to work you'd need to declare global $test; in the ZF action as well before including the file (which would be horrible).
Without knowing exactly what your legacy code looks like it's hard to suggest a good solution. If there are a set number of globals you need to work, you can global them at some point earlier in the ZF application (with the goal of removing that hack at a later date). If you don't know in advance what the globals are, or if there are a large number of them, you may need to edit the legacy code to try and refactor out the reliance on globals.
Another option (at least theoretically) is to use exec(), shell_exec(), passthru() (automatically prints output), or curl (see shell_exec link, but only if you're hosting it outside ZF2 to avoid an infinite loop). This approach has its own list of drawbacks including:
Security (but see escapeshellarg)
Access to $_SERVER (the first comment on the question here may help), $_GET (but see this technique), $_POST, and especially $_COOKIES
A bug (may be resolved) in the php command line

Is there a tool for PHP to find files that attempt to use undefined functions?

We have a large legacy codebase, and trying to find where a function is defined is quite the task. Luckily, modern IDEs have this covered. What isn't clear, however, is how (or, indeed, if) a file has already been included.
Our old-style code will often have a group of related functions in a single file, and prefix each function with the filename (so login_validate() will be in login.php).
example.php
<?php
require_once 'functions/login.php';
require_once 'functions/validate.php';
validate_something(); // Uses function defined in validate.php
echo user_login(), PHP_EOL; // user.php must have been included *somewhere* for this to work, but where?!
My question is: is there a tool that can scan PHP files and tell me which files will fail to execute, due to unresolved functions?
Note: Using PHP's built-in lint checker (php -l) doesn't catch this case.
PhpStorm is what I'd recommend. (In general, not just for this use.)
With it, you're able to do exactly this by running a project wide inspection. From the toolbar menu:
Code > Run Inspection by Name
Then a dialog will pop up asking for the type of inspection. Type in undefined function and hit enter. Then the next dialog will ask for the scope to run the inspection in, which is most likely your Whole project.

PHP Function Call Placement

Consider this snippet:
function f() {
return 'hi';
}
echo f();
Vs this snippet:
echo f();
function f() {
return 'hi';
}
When I run the scripts, they both produce the same results. That's great.
But my question is (and I could not find a good answer or reference in any of my searches), is it okay to call the function before it is defined (ie, from a sequential parsing of the script file perspective)?
I don't want to run into any issues or deprecation down the road if I leave the function call ahead of the function definition block in my script file.
From the Manual:
Functions need not be defined before
they are referenced, except when a
function is conditionally defined as
shown in the two examples below.
The possibility to call (reference) a function before it is defined is a PHP intentional feature and I don't think you need to worry about it becoming deprecated.
As an observation, if you can choose from declaring the function before or after, it would be common sense to declare it before it's used.
Note: The following code will give a fatal error because the function will only be defined at run rime.
<?php
echo helloWorld();
if(1){
function helloWorld() {
return 'hello world';
}
}
?>
compiler steps are like so:
Converts a sequence of characters into tokens
Analyses the tokens to determine there Grammatical structure.
Generates byte code depending on the outcome of the analyses
So the easiest way to understand this is just because the script is not multi threaded does not mean its processed in one in line execution.
PHP Reads your entire source code into tokens before its executed, there for it has control over the order of tokens should be executed first.
Take this example
while(true)
{
print '*';
}
Each line is a sequence of characters, so PHP Would interpret this as
if #T_IF
#T_WHITESPACE
(
#T_WHITESPACE
true #T_STRING
#T_WHITESPACE
)
#T_WHITESPACE
{
#T_WHITESPACE
print #T_PRINT
#T_WHITESPACE
'*'; #T_CONSTANT_ESCAPED_STRING
#T_WHITESPACE
}
but just because its been read does not mean its been executed.
So that functions are at the top of the list, this way you can execute them because there already within the systems memory.
I believe that the reason for this is that PHP's native library such as PFO,mysql_connect functions and classes are loaded first, and they move all user defined scopes to be loaded after there native implementations.
there loaded at the beginning of execution.
This is such a great question. Because it doesn't have a really good answer. PHP will, if given the chance, work just fine doing it backwards. Until it doesn't. And it won't if, for example, the function is defined in a yet-to-be loaded included file later on. PHP will include those files as they happen in code, so you will get a function not defined error in that case.
This is one SERIOUS gotcha in PHP.
It helps to imagine that includes are like copy/pasting whatever was in the other file into the code. But that it only happens when they get run in code. Which means they can be dynamic and based on the running code. But it also means they can't be pre-processed and linked up before-hand.
I find it a good practice to first define my functions and later call them, but it doesn't matters where do you put them as long they're there ;)
Also, i like to have my functions separated in different php files, depending on the use, just to be organized :)
No matter where you define your function and where you call. Because as far as I know, PHP server application first reads the whole page then executes it.

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