Reputation: 23
I wanted to implement a simple locking mechanism for few cron jobs and decided to do it in unusual way. It looks like PHP is a bit buggy when it comes to socket create/bind/listen.
A code that is working:
<?php
echo 'EXECUTING: '. __METHOD__ . \PHP_EOL;
if(false === ($socket = \socket_create(\AF_INET, \SOCK_STREAM, \SOL_TCP))) {
die('create');
}
if(false === ($bind = \socket_bind($socket, '127.0.0.1', 4444))) {
die('bind');
}
if(false === ($listen = \socket_listen($socket))) {
die('listen');
}
var_dump($socket, $bind, $listen);
This will create a socket, bind it to the interface wait for incoming connections. You can check it by invoking:
netstat -anp | grep LIST | grep tcp
If you take the same PHP code and put it into a simple class it won't bind/listen. Here is the code I'm talking about:
<?php
class Test
{
public function lock()
{
echo 'EXECUTING: '. __METHOD__ . \PHP_EOL;
if(false === ($socket = \socket_create(\AF_INET, \SOCK_STREAM, \SOL_TCP))) {
die('create');
}
if(false === ($bind = \socket_bind($socket, '127.0.0.1', 4444))) {
die('bind');
}
if(false === ($listen = \socket_listen($socket))) {
die('listen');
}
var_dump($socket, $bind, $listen);
}
}
$t = new Test();
$t->lock();
echo 'Working...'. \PHP_EOL;
sleep(60);
echo 'Done.';
Execute this code and you will see that var_dump will say that:
$socket
is a resource (which is what we want)$bind = true
$listen = true
but the code actually is not binding/listening.
What I am doing wrong?
EDIT:
Tested on:
Upvotes: 2
Views: 458
Reputation: 37365
The answer is simple: your $socket
variable is a local variable and it has no references rather that in method scope. That means, once method was executed, PHP will destroy all local variables - so $socket
as well. I. e. you're creating socket successfully and then PHP unset it in same moment (because method ends it's execution). Note, that unsetting local variables does not mean freeing memory immideately. Garbage collecting cycles is expensive, so PHP will do it only when memory limit will be reached.
To see difference, place sleep()
call inside method after socket's creation. PHP has garbage collection since version 5.3, so versions you've tried are affected. To see it in live, you can check this snippet:
class Foo
{
public function __destruct()
{
echo('destroyed'.PHP_EOL);
}
}
class Bar
{
public function test()
{
echo('starting method'.PHP_EOL);
$obj = new Foo();
echo('ending method'.PHP_EOL);
}
}
echo('start script'.PHP_EOL);
$obj = new Bar;
$obj->test();
echo('end script'.PHP_EOL);
with result
start script starting method ending method destroyed end script
-as you can see, class destructor was called immideately after exiting method call, because local $obj
variable has no references anywhere else.
Upvotes: 3