4

i have lets say 2 files lets say one index.php and other one included.php

index.php

<?php
include 'included.php';
while(true)
{
     $i++;
     sleep(3);
     $o = new tester();
}
?>

included.php

<?php
class tester{
public function __construct() {
//execute something
//wait for lets say one minute without stoping the flow of main loop.
//Rest code
}

?>

What i want is dont stop loop in index.php and when the tester class is provoked execute the first part and then wait for as i say one minute ?

Possible ? or do i need something else ?

j0k
  • 22,600
  • 28
  • 79
  • 90
kritya
  • 3,312
  • 7
  • 43
  • 60
  • 1
    "wait...without stopping the flow of the main loop" is possible by using process control to spawn separate processes (instances of the PHP script). Is that what you want? – George Cummins Jul 07 '11 at 16:22
  • maybe. If u can elaborate a little more – kritya Jul 07 '11 at 16:32
  • 1
    Read up about [fork call](http://php.net/manual/ru/function.pcntl-fork.php) and pcntl_* functions, though it won't work when PHP is used as Apache module. Mind the fork bomb. – sanmai Jul 12 '11 at 13:50
  • Look into Gearman (which would be another process entirely as others have mentioned, but takes care of a lot of issues for you). – Wrikken Jul 12 '11 at 21:50
  • @wrikken link to the german library pleae – kritya Jul 14 '11 at 16:22

7 Answers7

6

You cannot do this with PHP. It's not a multi-threaded language. You can vaguely simulate it by executing another copy of PHP in parallel ,but it's not true threading - it's two completely separate processes that happen to be executing the same script.

You cannot have two or more different parts of a script executing at the same time in a single instance of PHP.

Marc B
  • 356,200
  • 43
  • 426
  • 500
  • i know its not a multi threaded language but i heard there are some extensions/mod in it – kritya Jul 07 '11 at 16:36
  • Highly doubtful. Adding threads to PHP wouldn't be a simple mod. It's simply not a thread-safe language. – Marc B Jul 07 '11 at 16:37
  • something like piping or anything ? i need that :( – kritya Jul 07 '11 at 16:38
  • That'd be a command-line thing, and involve two separate PHP processes. You can use popen() to open a sub-php, but again it's completely separate from the parent script. – Marc B Jul 07 '11 at 16:39
  • Maybe we can write to a temp file and then read it by the other file ? – kritya Jul 07 '11 at 16:42
  • popen()'d processes can talk to each other via stdin/stdout without. if you want bi-directional communication, then use proc_open: http://php.net/proc_open http://php.net/popen – Marc B Jul 07 '11 at 16:48
  • @MarcB let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/1228/discussion-between-kritya-and-marc-b) – kritya Jul 07 '11 at 16:49
4

the question was very general but i don't think this is the right approach using php... usuaily php tries to execute things as quickly as possible for example rendering webpages. If you want to add timing and dynamic stuff like that would would have to send individual requests to the server every time you want to execute the script.

perhaps CRONJOBS or AJAX would be more appropriate for what you are trying to do.

Ruttyj
  • 853
  • 2
  • 11
  • 18
  • i am using CLI. And How can be cron jobs be used here ? =.= – kritya Jul 12 '11 at 04:04
  • Cron jobs can be used to fullfill tasks at certain time. Whatever your task needs to do in certain intervals, a cronjob could as well do in certain intervals. – Andresch Serj Jul 14 '11 at 12:45
2

You could write a new script testerStart.php which you access via url. That way you actually call another script on the server which will run idenpendently of your inital script.

So index.php would look like:

<?php
  while(true)
  {
     $i++;
     sleep(3);
     // call testerStart.php asynch
  }
?>

testerStart.php would look like:

<?php
  include 'included.php';
  $o = new tester();
?>
Community
  • 1
  • 1
pintxo
  • 2,085
  • 14
  • 27
  • Well yes. You will have to make sure you are the onlyone able to call this file. Possible ways of doing so is to generate some key which is stored on the server and only the caller and the called script know about, the script will only execute if the correct key was supplied. Or you could configure the server in a way that only localhost can access the testerStart script. – pintxo Jul 11 '11 at 07:15
  • 1
    @kritya You could create a random number once a day and write it to a file on the server (which of course should not be accessible to anyone except the server himself). You then supply this number to the called script. The script opens the file on the server, compares the content with the number it just received and done. – pintxo Jul 11 '11 at 08:52
1

You may want to look some the PCNTL functions in PHP. I don't have too much experience myself with it, but stumbled across it some time ago. It's not true threading by any means, but may bring you closer to what it sounds like you're trying to achieve.

Also if you have a PHPClasses account, a link I found may be relevant to you: a PHP PCNTL wrapper class.

theotherlight
  • 783
  • 1
  • 8
  • 12
  • Well i cant find a good way to how do i implement anything from phpclasses if u have some experience ? – kritya Jul 08 '11 at 05:49
  • I don't have any experience with this particular class, but there does seem to be some example uses on that page for download. – theotherlight Jul 08 '11 at 16:42
1

I'm not sure, but you can try something like

<?php
include 'included.php';
$instances = array();
while(true)
{
    foreach ($instances as $key => $instance) {
        if ($result = stream_get_contents($instance)) {
            pclose($instance);
            unset($instances[$key]);
            $o = unserialize($result);
            // do something with the object
        }
    }
    $instances[] = popen('php /path/to/include.php', 'r');
}
?>


<!-- in include.php -->
<?php
include 'included.php';
echo serialize(new tester());
?>

Or you can move all logic to "include.php" so the main script doesn't care about result at all, you will need to return just anything so that the main script knew that it may close the process handle.

Here we launch a script in separate process with popen('php /path/to/include.php', 'r'); and get a readable pipe to it (so we can read what that process outputs). When the object is successfully created in that separate process we serialize and output the result. Back in the main script with every iteration we check on already opened instances and if some of them returns something - we treat those contents as serialized object, unserialize it and then do with it whatever we want; then after doing what we wanted we close that process and remove it from opened instances list. Actually if that while(true) in your code doesn't really run forever but rather until certain condition is met - it would be a good idea to move the processing part to separate cycle, after the initialization... LIke

while($condition)
{
    $instances[] = popen('php /path/to/include.php', 'r');
}
while ( !empty($instances) ) {
    foreach ($instances as $key => $instance) {
        if ($result = stream_get_contents($instance)) {
            pclose($instance);
            unset($instances[$key]);
            $o = unserialize($result);
            // do something with the object
        }
    }
}
Slava
  • 2,040
  • 15
  • 15
  • 2
    Well... "Hello, it gives me some error" - "Try something". What does the error say? – Slava Jul 11 '11 at 12:50
  • See the edit for more explanation. And concerning your error... Well, isn't it obvious that since `new tester()` instantiation is launched in separate process then you must include any files used by `tester`? Or if problem isn't right there it's still something with your includes, you probably messed something with paths. – Slava Jul 11 '11 at 18:01
0

You'll indeed need a more complex setup.

You may indeed want to take a look at the pcntl functions as already mentioned, though these are only advised when using cli. When you need it in a web-app over Apache, you'll need to take a look at other solutions, because forking your process will not work.

Other solutions like the aforementioned popen are another good solution, though it may make your code dependent from your architecture (paths on unix are different from paths on windows, you'll need to be certain that 'php' is callable, ...)

If both of the above possibilities are no option, I'd suggest doing an async http request using either curl of fsockopen with stream_set_blocking disabled. It'll be quite a lot of work however, but the async call will get the background script running and your parent script can simply continue. Then inside your loop in the parent process, occasionally check if your background script has already been completed - with fsockopen: stream_get_contents($resource) until feof($resource)

matthiasmullie
  • 2,063
  • 15
  • 17
0

I researched more and used my mind and finnaly i found out a way myself i did this :

index.php

<?php
$cmd = "php -q nah.php";
exec($cmd);
while (true)
{
sleep(1);
echo "lalal";
}
?>

included.php

<?php
echo "yaya";
sleep(3);
?>

And this worked as a charm

kritya
  • 3,312
  • 7
  • 43
  • 60