Are php statements executed synchronously? - php

Ok this seems like a stupid question that I should certainly know the answer to, but I've got some weird behavior where the constructor of one of my classes checks to see if a table exists, if not it creates it.
The strange thing is when the table doesn't exist, if the constructor is called multiple times then it doesn't see the table that should have been created on the first constructor call.
Are all function calls synchronous in PHP?
For example:
f1();
f2();
Does the interpreter wait for f1() to return before calling f2()?

Does the interpreter wait for f1() to return before calling f2()?
Yes, even if f1() kicks off other asynchronous tasks.

Related

Can two parallel invocations of a static method exists in PHP?

What will happen if same static method is called by two parallel threads?
Will it make one thread waiting or can two parallel instances of a static method exists?
Assume function don't use member variables and only use local variables.
Example:
<?php
public class ClassName{
public static function doStuff(){
// Function code goes here
}
}
?>
Assume this function is called by GET request to the server. Then if two users send a call to the URL exactly at same time, then what will happen?
See Confirmation that PHP static variables do not persist across requests for the information you need.
Standard PHP does not do any locking or waiting. It will just run the method and the 2 seperate request do not known of each other and they can't access each others memory(In the given case).
This is a race condition. It depends which request gets processed first. A http request is handled by a webserver and the webserver spawns a php process to process the php script.

When exactly is the autoloader called?

I have an autoloader that is registered using spl_autoload_register():
class MyAutoLoader{
public function __construct(){
spl_autoload_register(array($this, 'loader'));
}
public function loader($className){
var_dump($className);
}
}
$al = new MyAutoLoader(); //Register the autoloader
From the var_dump(), the autoloader seems to be called on lots of things, things that are data to be inserted into a database, parameterized SQL queries and what not:
string 'name' (length=4)
string 'a:2:{s:5:"label";s:4:"Name";s:8:"required";b:1;}' (length=48)
string 'en_US' (length=5)
string 'object' (length=6)
string 'name = ?' (length=8)
These things will never be classes so should never be loaded using new or class_exists(), etc.
Under what circumstances/function calls are autoloaders called? I would like to put a stop to autoloading "classNames" that are not classes from being called, because each $className is checked using file_exist(), and having these data strings checked is pretty inefficient.
Problem resolved. I first did a back trace as suggested by Brad and dumped the traces to a file (just add a small snippet that opens a file and appends to it).
Obviously, the trace was very big, but I picked the simplest one I could find. Incidentally, that trace happened to be one that called a database (ORM) wrapper I have written to wrap around the awesome RedBean ORM library. The results from me dumping $className also validates that, because those strings are data are going into or coming out of the database.
Having said that, I have a __call() that intercepts methods to my database wrapper, does some processing, pass it to RedBean, process the result, and then sends it back to the caller.
Problem: During the processing, I am making calls to is_subclass_of() and instanceof, which will obviously ask the autoloader to try and load the class (since we don't have any class called name =? loaded, nor does it exist).
The solution was to actually make sure we have an object before calling is_subclass_of() and instanceof: if(is_object($someproperty) && is_subclass_of($someproperty)).
If $someproperty is not an object, the if immediately short-circuits and instanceof and is_subclass_of() is never called, which means the call to the autoloader is never made.
As mentioned by brad, having all sorts of things going to the autoloader to be included using require_once can be a huge security risk and at the same time, hitting the file system so many times using file_exists() is pretty inefficient too.
So, in conclusion, the autoloader is called every time you use instanceof, is_subclass_of, other class-type functions, class-exist functions and reflection methods, as Charles motioned in his answer.
So, the moral of the story is that if you plan to use a class-type function, or any of the functions mentioned above on a variable of mixed type, check it first before passing it to the class-type function.
Under what circumstances/function calls are autoloaders called?
I realize that this has ended up basically being a secondary question given the problems noted in the comments, but it's still worth answering.
Autoload functions, that being a __autoload() function in your code or callbacks registered through spl_autoload_register, are called when -- and only when -- PHP needs to access a class that has not been defined. This is done everywhere with few exceptions, such as class_exists, which have arguments that tell PHP not to call any autoloaders.
The PHP manual has a page dedicated to autoloading. I recommend reviewing it if there's any confusion.
You can use debug_backtrace or debug_print_backtrace to find out where exactly the auto-loader function is being called.
Technically it should only be called by PHP when a script references a class name that does not exist.

PHP - Using a method similar to forking to define one constant multiple times? (Windows)

I'm currently working with an existing application that defines a couple constants on the login of a user. For example, if Alice logs in SOME_CONSTANT is defined as 1, while if Bob logs in SOME_CONSTANT is defined as 2. Now I'm trying to write a script that will do a couple of things as if it were Alice and a couple things as if it were Bob. By "as if it were" I mean that SOME_CONSTANT is defined one way for one iteration and another way for the next iteration. Unfortunately, constants are not the best at switching values and refactoring the application to change these from being constants is not an option at this time.
One method I had considered was to use pcntl_fork(). I would fork before the time the constants were defined and run a separate process for each constant. However, I would like this script to be able to run on Windows as well as Linux. At the moment the pcntl extension is not directly supported for Windows. And I'm going to try to avoid getting everything working through Cygwin if I can help it.
Another method I had considered was having the script call children scripts using exec("php childscript.php constant_value"). Will this method allow one child script to define a constant one way and another child script define it another way? I think it should, but I haven't tested it yet. Also, is there any other major problems anyone can see with this method?
Is there another method I haven't considered that would be a better choice? Thank you for your time.
As you've already noticed, using a const variable is not a viable method to handle your task. Additionally, even if you didn't need to write a script to do something with multiple users, a single instance of this wouldn't work - you would need to "set the constant" when the user logs in, which you can't do.
If you're looking for a pseudo-readonly implementation, and you are using OOP-style, you can add a private variable and override the __get magic-method. So, whenenver the outside requests SOME_CONSTANT, your class will return the value of _someFakeConstant. Then, in your login() or switchUser() method inside the class you can safely change the value.
Example:
class User {
private $_someFakeConstant = -1;
public function __get($name) {
if ($name == 'SOME_CONSTANT') {
return $this->_someFakeConstant;
}
// handle undefined variables; trigger_error() will work (see example on php.net)
}
public function login() {
// logic to "identify" the user
$this->_someFakeConstant = 1;
}
}
$user = new User();
$user->login();
echo $user->SOME_CONSTANT;
The method of using exec() to call the PHP child script appears to work fine.

mysql query on class destruct

Is it OK to perform a mysqli query on a class __destruct function?
I heard somewhere it will not always finish the query or it won't work as expected.
For example:
class stackoverflow{
function a() {
}
function b() {
}
function __destruct() {
//mysqli query here
}
}
Generally, you are better of creating your own method to carry out any work that needs to be done toward the end of the script and call it manually.
The principle reason for this in my view, is error handling.
According to the online documentation:
Attempting to throw an exception from a destructor (called in the time of script termination) causes a fatal error.
This means that should an error arise - for example - in your mysql query, a fatal error will shutdown your script.
a __destruct method may well be useful at times, but better used in situations that only require some simple hard-code, which is tested and not error prone.
Additionally, some servers may change various parameters during the shut-down phase. Such as the working directory.
There's no reason why it shouldn't work as expected. However, it would help if you explained why you wanted to do so in the first place, there may be a better solution than what you have in mind

Deconstructor in PHP

After taking a look at some old code:
//Nothing like a destructor!!
function destroy() {
settype(&$this, 'null');
}
And called by
$Cache->destroy();
However in PHP 5.3 I get
Deprecated: Call-time pass-by-reference has been deprecated in /blah/-cache-.php on line 154
How should I do this?
Your immediate problem can be met by removing the & in $this, but the whole construction doesn't make sense to me. If it's not plain invalid to destroy $this from within the object's context, it's definitely not good practice.
To destroy an object, a simple
unset($Cache);
will do.
If one wants to execute stuff when the object is destroyed, one should define a destructor in the class. (The comment in your destroy() code says that this is not the point here, though. :)
Just destroy the object like normal.
unset($Cache);
I don't know why they would do that nasty looking mess above. Keep in mind that if the object has pointers in different places you will need to unset all of them - not just that one line. (singletons are an example)
The error you're getting is not related to having a destructor. The error is simply because you've tried to pass $this by reference in a function call.
PHP used to allow this, but in current versions of PHP, if you want to pass something by reference, you should specify it in the function declaration.
Therefore, your function call should look like this:
settype($this, 'null');
(ie without the &). (btw -- the word 'null' in a string??? is that what you meant?)
And if you want to pass by ref, your function should look like this:
function settype(&$object, $secondparameter) {
...whatever the function does...
}
ie with the & in the function parameter.
This rule applies in all cases in PHP. As I said, it has nothing to do with your destructor method, or with it being an object; that's just how you pass by reference in modern PHP.
Now onto the other part of your question: A destructor method.
PHP does allow for an automatic destructor function, written within your class like this:
function __destruct() {
print "Destroying " . $this->name . "\n";
}
If you write this code, the __destruct() method will be called when the object is destroyed. This may or may not be what you want -- depends on how you want it to work. The object will be destroyed when all references to it are unset or come out of scope. If you're passing the object handle around by reference, this may not happen when you expect it to -- ie the object may persist in memory even when you say unset($myobject);. In this case, it may only actually get destroyed when the PHP program finishes running. If this is the case, and you need it to be called sooner than that, you may be fine continuing with the destroy() method you have already, and calling it explicity.
Hope that answers your question.

Categories