Understanding PHP declare() and ticks - php

Today I was looking through the php manual and stumbled upon a control structure declare.
The declare construct is used to set execution directives for a block
of code
This is what declare is supposed to do. To be honest I didn't understood it. On reading again it found a new thing Ticks
A tick is an event that occurs for every N low-level tickable
statements executed by the parser within the declare block. The value
for N is specified using ticks=N within the declare block's directive
section.
I didn't understand it either. what does it mean by N low-level tickable statements If there had been a good sample code, then it would have been easy to understand. But none was found in the manual. I have found some on SO Q1, which actually increased my curiosity and confusion. So can anyone what is this for and where can we use this.
My actual confusion is with this statement (from the linked so post) you can declare a tick-function which checks each n executions of your script whether the connection is still alive or not. So when I register a tick function with tick = 20 on a php file and execute it, the file will be alive till 20 execution is complete(got this idea when it was wrongly considered as multithreaded). This is the idea i have got, I dont think its correct..
Or is it a simple replacement for while($x = 20)
[EDIT 1]
I have also seen the implementation of declare() another section of php manual Function arguments
[EDIT 2]
Also in Process Control
You use the declare() statement to specify the locations in your
program where callbacks are allowed to occur. This allows you to
minimize the overhead of handling asynchronous events

When PHP is executing your script, the execution can be seen as a lot of statements being executed. Most statements cause a Tick, though not necessarily all statements do so. (Manual says: Typically, condition expressions and argument expressions are not tickable.)
This block would normally cause 5 ticks, as you are executing 5 statements:
$a = 1;
$B = 2;
$a = 3;
$B = 4;
$a = 5;
And this block would normally cause 5 ticks, and one more tick as the end of the while loop also is counted as a statement/tick:
while ($i < 5)
$a++;
With the help of declare(ticks=N) and register_tick_function(), you can now execute code in between the statements/ticks. The register_tick_function specifies which function should be called when a tick event occurs. And the declare sets how many tick should pass, before a tick event occurs.
With declare(ticks=1) and register_tick_function('someFunction'); you will call someFunction() code in between every statement/tick.
If you use declare(ticks=3), then someFunction() will be executed on every third statement/tick.
Example:
function handler(){
echo "x";
}
register_tick_function("handler");
$i = 0;
declare(ticks = 4) {
while ($i < 9)
echo ++$i;
}
This script will output: 1234x5678x9
It's that simple.
Now what is meant in the linked question with "whether the connection is still alive", is not really interesting on itself and is not actually related to the above mentioned. It is just something you COULD do on every tick event. But you can also do something totally different. What is mentioned is simply that some scripts can take quite some time to execute and that during the execution, the client can disconnect. (Imagine closing the browser, while the script is still running.) PHP will by default continue to run the script, even if the client has disconnected. You can use the function connection_aborted() to detect if the client has disconnected. This is something you COULD also do without using ticks at all.
Now let's say for example that you want your script to stop running as soon as the client disconnects. Simply use ...
function killme() {
if (connection_aborted()) {
die();
}
}
register_tick_function('killme');
declare(ticks=1);
... and your script will call killme() after each statement of your code. killme() will check if the client is still connected and die() when it isn't.

In practice: Ignore the declare() directive. Unless you run into code that makes use of it — which is very rare — you can safely forget that it ever existed.
That being said, here's the details. The declare() directive is currently used for two completely unrelated things:
As declare(encoding=…), for declaring the encoding of a PHP file. (In this sense, it's comparable to a server-side version of <meta charset="…">.)
But don't use this. Under most circumstances, the script encoding doesn't matter. If by some chance it does, the PHP encoding should be set globally (hopefully to "UTF-8") by the zend.script_encoding configuration value. Setting it at the file level is confusing and unnecessary.
As declare(ticks=…), for defining the frequency at which tick functions are called. Tick functions are called periodically by the PHP interpreter, and are set up using register_tick_function.
While some of the comments on php.net suggest using it to implement timeouts on network accesses, that doesn't actually work as expected, as ticks are not fired while the interpreter is blocked in a native function call. It might have some applications in benchmarking, but outside of that it's basically useless. I'd avoid it.

The one usage not mentioned in this or the possible duplicate answer is catching signals.
If you have a CLI script and want to catch user signals (like SIGHUP or SIGTERM (CTRL+C)), you need declare(ticks... together with pcntl_signal https://secure.php.net/manual/en/function.pcntl-signal.php which allows you to catch those signals (same like trap in shell scripts)

Related

Correct placement of functions in PHP code [duplicate]

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.

is there a way to eval a piece of php code where die() or exit() is present and return to main code if it is called?

I do not have control over the code I'm executing. This is a third party function, but not user-entered. These are things that are versioned so it is impractical that I poke there and change all die()'s into something more sane. Because a new version is coming from time to time and then I could paradoxically make the code even more insecure by trying mess with it poor error handling.
so let's say we have a function:
fuction myfunc() {
// lot's of complicated code
if (!is_file('myfile.txt') exit('file not found');
// and so on
}
What I'm trying to do is to somewhat run that piece of code and return to my main thread and then act accordingly with that error.
I've tried die() or eval() but this returns the whole script.
Bummer ?
A Hail Mary approach is to use runkit's runkit_function_redefine or function_override to redefine the functions die and exit to throw an Exception instead.
A potential problem is that the 3rd party can catch those exceptions and might not deal with them correctly. It's also very likely that you can't properly deal with the exception either.
You can use register_shutdown_function to run code after exit has been called. You are somewhat limited in what you can do at this point as some services have already been shut down (such as autoloading). I think you can still output content, not sure about sessions and other headers.
Another approach would be to run the code in a seperate php process (or http request), for instance by calling php through exec.
A more solid approach can be to add predicitions to your own code, ensuring the bad states are never reached when calling the 3rd party code. It is possible that not all preconditions can be met.
Ideally only code that is an entry point (like a router script) may exit. Using exit anywhere else is just shoddy programming really.
If you have not read Halcyon's answer, you should have a look at it first.
Since you mention eval(), I assume you have the code as a string. I will refer to both die() and exit() by just the latter, but things should be relevant for both.
You can try and replace occurrences of die() and exit() with something, and then eval. It's simple but that can be very messy.
One thing to look out for, IF you decide to do this, is that you may end up replacing occurrences which are not really 'code'. For example, echo "Let him exit()";.
Also, when you consider possible equivalent syntax, like exit (); , exit; or exit(1);, it gets much more unpleasant. You'll have to handle those with a regex.
But if you can safely assume that
those two signatures (die() and exit()) are the only ones you need to worry about; and
that strings (or other content) are not going to contain those 'phrases'
then you can use this approach.

Why if/else vs. or/exit in PHP?

Seeing the exit() PHP documentation got me thinking:
$filename = '/path/to/data-file';
$file = fopen($filename, 'r')
or exit("unable to open file ($filename)");
Couple questions:
What are common use cases besides opening files for using exit()?
Since not every function everyone ever writes ends in exit(), how do you know to use it in some contexts vs. others?
Are if/else and or/exit interchangeable?
In that context, the or in that statement is one of PHP's logical operators which when used like that, will execute the second statement if and only if the first one fails due to short circuit evaluation.
Since fopen returned false, the or exit statement gets executed since the first part failed.
To understand it better, here is a quick explanation of short-circuit evaluation.
$x = 5;
$y = 42;
if ($x == 5 or $y == 42) {
echo "x or y is true";
}
In the above code, the expression $y == 42 is never evaluated because there is no need since the first expression was true.
In that example, they are using the same logic for deciding whether or not to evaluate the statement that calls exit.
To address your questions:
I wouldn't use exit when opening a file failed unless the program was very specific. The better thing to do would be to log an error and then return the error to the caller so they can decide what to do.
When to use exit completely depends on the code you are writing.
Given the explanation about short-circuiting, yes they are interchangeable in that sense. Using or exit is just a bit shorter than using if/else.
Hope that helps.
CLI scripts, exit can take an integer parameter which is fed back to the console to indicate success or some form of error
I'm not inclined to use exit() or die() in application code, since exceptions are preferred. However, I personally think you might be overcomplicating things a little bit... it kills script execution, so use it when you need to kill a script. Truthfully I mostly only ever kill scripts mid-execution when debugging (one-off breakpoints) and that's not ideal either (again exceptions do a better job).
The use of or is mostly convenient. Here's an interesting point though...
Why does
$resource = mysql_connect() || die('dead')
not work?
The answer is that the = operator takes precedence over or so that the assignment is made first like so: ($resource = mysql_connect()) or die(). In this way its exactly like doing an if(!($resource = mysql_connnect())) { die() }
I tend to avoid using exit() at all as it's a really ugly way to handle errors from the user's perspective.
If you must use it, any non recoverable error would be a candidate. For example, database query or connection failures, or remote request failures.
if/else is equivalent to ...or whatever(). It's just a style thing, with the latter form being more succinct.
I would say you use exit in a situation where your code cannot continue if the function you were doing failed. For example reading a file that is needed.

exit, exit(), exit(0), die(), die(0) - How to exit script

I believe that all of these (and even die() or die(0)) are identical. If they are not identical, which is preferred for exiting a script successfully? If they are identical, is there any preferred standard to indicate successful script completion? I tend to use exit;.
EDIT: All of the answers have "die() and exit() are identical" even though I say that in my question. I updated to the title to hopefully make it clearer that this is NOT my question. I want to clearly indicate success from a command line script.
These are all identical. I'm pretty sure die() is just a straight-up alias to exit(), but even if it isn't, it still acts identically.
When one of these functions is given a string argument, it prints out the string before terminating the process. When it encounters an integer under 255, that integer is considered the return code for the process, which gets passed back to the process which invoked the PHP script. This is particularly useful when writing command line applications (PHP isn't web-only!).
As far as the difference between exit, exit(), and exit(0), there really is none. There is definitely no difference between the first two because exit is technically a language construct, not a function, so it can be called with or without parentheses, just like echo. Returning a code of 0 means "this program ran successfully/without errors", and while I don't know what exactly happens when you don't pass an argument, PHP.net says that an argument-less exit indicates success, so I would bet it returns 0, though again PHP.net doesn't show a default for the argument.
As several people have mentioned, die() and exit() are exactly the same.
If you look at the PHP documentation, there are two options for arguments:
An numeric value. This is only useful if you are using PHP from the command line, as opposed to a web server. A value of zero indicates success. Nonzero indicates a failure condition occurred.
A string value. This will be displayed to the browser when the exit occurs.
Instead of die() or exit(), I recommend using exceptions and a custom top-level exception handler to manage failure conditions.
You have more flexibility that way to do things like automatic error logging. Also, if you're using PHP to implement a JSON API, this exception handler can hand back a valid, error-indicating JSON snippet instead.
I would say that in regards with a better semantics die($arg); should be used for an abnormal or unexpected termination, even when -of course- you still have caught it. And exit($arg); should be used for a normal (expected / controlled) end of a process, like in break; for a for or while or a switch structure but with a definitive end.
Nevertheless .. I personally often use a general if { } else { } structure to control different branches of huge processes or output buffering so not having to use "exit" ..
I also use die($arg) in simple error-catching semantics like in
$db = mysql_connect([$args]) or die ($error); ...
die(); is just a synonym for exit(); and is functionally identical.
The standard way is to use exit code zero to signify success, and anything else to denote an error condition.
die() is typically used to kill the script with an error output:
die("There was a fatal error");
where-as exit is typically used as a successful exit (At least in my coding)
The PHP Manual says that the functions are identical.
I will get downvoted to hell, but in some cases when hacking in CLI, we do not want the program to get killed, while not wanting to continue the full execution.
Here the goal is to avoid making api calls to a separate hand-point file. Say I have a nice play button in my interface, that execute system calls.
Example 1: The program get killed after the job , no datas returned. This is not wanted.
if ($_GET["play"] != ""){
// Some job
exit;
}
/* Huge amount of data*/
Example 2: The program still runs, feeding the whole data in the GET request. This is unnecessary on this case. This is slowing down the browser with all the data, that he has already.
if ($_GET["play"] != ""){
// Some job
}
/* Huge amount of data*/
Example 3: The program still runs, no data returned as expected, the play command had been executed, but the whole data set get parsed, this is unnecessary job, can slow down php/the machine.
/* Huge amount of data*/
if ($_GET["play"] != ""){
// Some job
}
Example 4: The program still runs, no data returned as expected, the play command had been executed, the whole data had not been parsed, php returned super quickly 200OK with an empty response, as expected. Everyone happy!
if ($_GET["play"] != ""){
// Some job
goto END;
}
/* Huge amount of data*/
END;
Yes! Using GOTO, sometimes is to be considered -as the best to do 🔨 -!
https://www.php.net/manual/en/control-structures.goto.php
die is exactly equivalent to exit.
From the manual:
If status is an integer, that value will be used as the exit status..
This is only useful if you have some sort of wrapper that does something based on the exit status. Unless you have a specific need to report an exit code to the outside world, just exit;.

How to sandbox a request to another PHP script?

I have a primarily Ajax-driven site, the content of which is populated by making requests to an "operator" PHP script.
While typically these requests originate in Javascript, there are occasions when it's useful to query my operator from within another PHP script.
The method I have been using is to pass a URL with query string through file_get_contents() — and then to parse the returned JSON with json_decode().
For multiple reasons, I'd like to avoid this implementation, though... I see in my error logs that the URL requests are a lot more susceptible to failure for whatever reason — and I've read that it's not very efficient.
My 1st attempt to make a generic query_operator($query_string)-type function simply require()-ed operator.php within an output buffer, captured with ob_get_contents(). I also temporarily reset the $_REQUEST array with parameters parsed from the $query_string.
This approach had too many shortcomings — problems with variable scope and the MySQL connection, specifically.
My 2nd attempt involved using the backtick operator (equivalent to shell_exec()), and mapping the $argv arguments to the $_REQUEST array.
This approach actually works very well, but on the host I'm using, the PHP (cli) version is set a 4.4.8 — and I need 5.2.x. Assuming I can't switch the (cli) version, what's the next best way to sandbox a request to another PHP script, with a query string? Any suggestions greatly appreciated.
Here's what my 2nd attempt looks like:
function query_operator($query) {
$query = '--'.str_ireplace('&', ' --', $query);
$contents = `php operator.php $query`;
if ($json = json_decode($contents, true)) {
return $json;
} else {
return $contents;
}
}
The best thing to do, in the long run, is to factor your code.
Whatever logic operator.php is doing that is needed should live in some library, which can then be used by operator.php and any other script that needs it.
When you do that, you'll avoid all the overhead of an extra PHP process, communication between two processes, and probably all your json-encoding/decoding.
If factoring is too much work to take on now, either of the strategies you describe should work as a kludge. It might be worth looking into why your make-a-loopback-http-request method (the first thing you described) caused errors. It really ought to work well, even if it's inefficient.

Categories