简体   繁体   中英

Share variables/memory between all PHP processes

Is it possible to share variables and arrays between all PHP processes without duplicating them ?

Using memcached, I think PHP duplicates the used memory:
$array = $memcache->get('array');
$array will contain a copy from memcached.

So my idea is, there could be a static variable that was already defined, and shared between all processes.

Using Shmop :

Shmop is an easy to use set of functions that allows PHP to read, write, create and delete Unix shared memory segments.

from: http://www.php.net/manual/en/intro.shmop.php

No external libraries are needed to build this extension.

The shared Memory Functions

  • shmop_close — Close
  • shared memory block
  • shmop_delete — Delete shared memory block
  • shmop_open — Create or open shared memory block
  • shmop_read — Read data from shared memory block
  • shmop_size — Get size of shared memory block
  • shmop_write — Write data into shared memory block

Basic usage

// Create 100 byte shared memory block with system id of 0xff3
$shm_id = shmop_open(0xff3, "c", 0644, 100);
if (!$shm_id) {
    echo "Couldn't create shared memory segment\n";
}

// Get shared memory block's size
$shm_size = shmop_size($shm_id);
echo "SHM Block Size: " . $shm_size . " has been created.\n";

// Lets write a test string into shared memory
$shm_bytes_written = shmop_write($shm_id, "my shared memory block", 0);
if ($shm_bytes_written != strlen("my shared memory block")) {
    echo "Couldn't write the entire length of data\n";
}

// Now lets read the string back
$my_string = shmop_read($shm_id, 0, $shm_size);
if (!$my_string) {
    echo "Couldn't read from shared memory block\n";
}
echo "The data inside shared memory was: " . $my_string . "\n";

//Now lets delete the block and close the shared memory segment
if (!shmop_delete($shm_id)) {
    echo "Couldn't mark shared memory block for deletion.";
}
shmop_close($shm_id);

One way to share memory between PHP processes is to install a PHP-bytecode cache like APC . APC is primarily used for storing the bytecode into an OS managed shared-memory segment, but it also has an API for sharing anything you want between processes (like a local version of memcache).

<?php
   $foobar = array('foo', 'bar');
   apc_store('foobar', $foobar);
?>

Then elsewhere:

<?php
    $foobar = apc_fetch('foobar');
    var_dump($foobar);
?>

The big problem with sharing-memory is that it becomes very easy for two processes to step on each other's foot. So shared memory is best for things that don't change too much, like big global arrays.

PHP has magic methods:

  • __get($property) let us implement the access of a $property on an object
  • __set($property, $value) let us implement the assignation of a $property on an object

PHP can serialize variables:

  • serialize($variable) returns a string representation of the variable
  • unserialize($string) returns back a variable from a string

PHP can handle files, with concurrent-access management:

  • fopen($file, 'c+') opens a file with advisory lock options enabled (allow you to use flock)
  • flock($descriptor, LOCK_SH) takes a shared lock (for reading)
  • flock($descriptor, LOCK_EX) takes an exclusive lock (for writting)

So, the easiest way to share an object between apps is to create a class that implements and use all those stuffs to save and restore instantly all its data into a file.

A simple implementation of that class could be :

class Synchro
{

   private $_file;

   public function __construct($file)
   {
       $this->_file = $file;
   }

   public function __get($property)
   {
       // File does not exist
       if (!is_file($this->_file))
       {
           return null;
       }

       // Check if file is readable
       if ((is_file($this->_file)) && (!is_readable($this->_file)))
       {
           throw new Exception(sprintf("File '%s' is not readable.", $this->_file));
       }

       // Open file with advisory lock option enabled for reading and writting
       if (($fd = fopen($this->_file, 'c+')) === false)
       {
           throw new Exception(sprintf("Can't open '%s' file.", $this->_file));
       }

       // Request a lock for reading (hangs until lock is granted successfully)
       if (flock($fd, LOCK_SH) === false)
       {
           throw new Exception(sprintf("Can't lock '%s' file for reading.", $this->_file));
       }

       // A hand-made file_get_contents
       $contents = '';
       while (($read = fread($fd, 32 * 1024)) !== '')
       {
           $contents .= $read;
       }

       // Release shared lock and close file
       flock($fd, LOCK_UN);
       fclose($fd);

       // Restore shared data object and return requested property
       $object = json_decode($contents);
       if (property_exists($object, $property))
       {
           return $object->{$property};
       }

       return null;
   }

   public function __set($property, $value)
   {
       // Check if directory is writable if file does not exist
       if ((!is_file($this->_file)) && (!is_writable(dirname($this->_file))))
       {
           throw new Exception(sprintf("Directory '%s' does not exist or is not writable.", dirname($this->_file)));
       }

       // Check if file is writable if it exists
       if ((is_file($this->_file)) && (!is_writable($this->_file)))
       {
           throw new Exception(sprintf("File '%s' is not writable.", $this->_file));
       }

       // Open file with advisory lock option enabled for reading and writting
       if (($fd = fopen($this->_file, 'c+')) === false)
       {
           throw new Exception(sprintf("Can't open '%s' file.", $this->_file));
       }

       // Request a lock for writting (hangs until lock is granted successfully)
       if (flock($fd, LOCK_EX) === false)
       {
           throw new Exception(sprintf("Can't lock '%s' file for writing.", $this->_file));
       }

       // A hand-made file_get_contents
       $contents = '';
       while (($read = fread($fd, 32 * 1024)) !== '')
       {
           $contents .= $read;
       }

       // Restore shared data object and set value for desired property
       if (empty($contents))
       {
           $object = new stdClass();
       }
       else
       {
           $object = json_decode($contents);
       }
       $object->{$property} = $value;

       // Go back at the beginning of file
       rewind($fd);

       // Truncate file
       ftruncate($fd, strlen($contents));

       // Save shared data object to the file
       fwrite($fd, json_encode($object));

       // Release exclusive lock and close file
       flock($fd, LOCK_UN);
       fclose($fd);

       return $value;
   }

}

Now, you can use this class like stdClass , but with a file path when constructing.

$obj = new Synchro("/tmp/test.sync"); 
$obj->hello = 'world';

// ... and in another process...
echo $obj->hello;

This example is of course very simple, it takes care about concurrent access to a file but not to a variable, in a better implementation you'll use a mutex-like lock.

I just pushed this class (after completing it) on github, you can find it here .

By default its simply not possible. Every solution will always copy the content into the current scope, because if not, there is no way to access it.

I dont know, what exactly want to do, but maybe you can do that "outside", for example as a gearman job, and then just catch the results of the process, instead of the whole array.

You can also think about splitting the "big" array into slices and then always retrieve the part you currently need from an apc or memcached.

Edit:
You are probably using shared memory wrong way.
Your shared memory itself being such array. So you have to store separate multilanguage strings directly in shared memory, not big array with them.
and then only pull strings, required on particular page.
that's all.

In general, to process some data, a program have to "duplicate" it, by storing it in a variable.
That's what variables are for - to store (or "duplicate") some outside data.
For example, if you have some user info in your database, to display a username on a web page you have to "duplicate" this data, storing it in PHP variable first.
And so on.

You are first who thinks that such approach needs to be changed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM