Сколько не говори о PHP все равно к нему прилипло не мало мифов. Сегодня я развею несколько мифов используя PECL расширение Alternative PHP Cache. Это не много больше чем расширение — это кешер опт кода.


Миф 1. PHP нужно каждый раз конфигурировать приложение


Начнем развеивание мифов с того, что сегодня без PHP акселераторов почти никто не работает. Кто-то может называть их костылями, но факт того, что голый php работает «немного расточительно» просто обязал разработчиков задуматься, над оптимизацией процесса обработки PHP приложений. Итак посмотрим на пример конкурирования приложения 1 раз:

Код
$constants = array(
"REVATIVE_PATH"=>"",
"DB_PREFIX"=>"diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_diafan_",// для наглядности примера
"DB_CHARSET"=>"utf8",
"ADMIN_FOLDER"=>"admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/admin/",
"USERADMIN"=>true,
"CACHE_MEMCACHED"=>true,
"CACHE_MEMCACHED_HOST"=>"localhost",
"CACHE_MEMCACHED_PORT"=>"11211",
"TIMEZONE"=>"Europe/Moscow",);
apc_define_constants('numbers', $constants);// первый раз читаем конфигурацию
?>

<?php //Второй раз загружаем конфигурацию\
function mUsage($usage, $base_memory_usage, $k) {
    echo "\n";
    echo 'Разница использования памяти внутри скрипта в байтах: ' ,$usage - $base_memory_usage, $k;
    echo "\n";
}
$base_memory_usage = memory_get_usage();
apc_load_constants('numbers');
mUsage(memory_get_usage(), $base_memory_usage,' - загрузился доступ к ссылкам на константы.');
$base_memory_usage = memory_get_usage();
echo REVATIVE_PATH, DB_PREFIX, DB_CHARSET, ADMIN_FOLDER, USERADMIN, CACHE_MEMCACHED, CACHE_MEMCACHED_HOST, CACHE_MEMCACHED_PORT, TIMEZONE;
mUsage(memory_get_usage(), $base_memory_usage , ' - были использованны только ссылки.');
$base_memory_usage = memory_get_usage();
$m= REVATIVE_PATH.DB_PREFIX.DB_CHARSET.ADMIN_FOLDER.USERADMIN.CACHE_MEMCACHED.CACHE_MEMCACHED_HOST.CACHE_MEMCACHED_PORT.TIMEZONE;
mUsage(memory_get_usage(), $base_memory_usage, ' - мы записали константы в нашу переменную.');
?>


Результатом будет:
Разница использования памяти внутри скрипта в байтах: 208 - загрузился доступ к ссылкам на константы.
...
Разница использования памяти внутри скрипта в байтах: 0 - были использованы только ссылки.

Разница использования памяти внутри скрипта в байтах: 504 - мы записали константы в нашу переменную.

Как я и говорил, по сути мы 1 раз сконструировали скрипт и не тратим лишний раз память и ресурсы на инициализацию переменных и конфигурацию переменных. 208 байт кстати выделяется независимо от количества констант и данных в них.

Миф 2. В PHP нельзя вот так вот просто взять и перекинуть информацию из воркера в воркер


Как мы обычно перекидываем информацию? обычно с помощью БД или записываем данные в фаил, или используем относительно медленный Memceched.
Мы будем перекидывать информацию используя:
apc_store();  // переназначает значение переменой
apc_fetch();  // возвращает значение переменной
apc_add();   // если не определена переменная то присваивает ей значение

Проведем синтетический тест чтобы понять насколько быстро мы будем перекидывать информацию:
Код теста
$a = microtime(1);
$b = microtime(1);

class q{
public $i;
public function c($i, $e) {
$this->i[$i]=$e;
}

public function r($i) {
return $this->i[$i];
}

public function i($i, $e = 1) {
$this->i[$i]++;
}}

function c($w, $e) {
global $$w;
$$w = $e;
}

function r($w) {
global $$w;
return $$w;
}

function i($w, $e = 1) {
global $$w;
++$$w;}

$base_memory_usage = memory_get_usage();
// Для чистоты эксперемента сделаем вот так
$q=new q();
//apc_store('object q',$q);
memoryUsage(memory_get_usage(), $base_memory_usage,' — инициализзация класса');
$base_memory_usage = memory_get_usage();
$a = microtime(1);
for (c('i', 0); r('i') < 1000000; i('i')) {
c('is', 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'.r('i'));
}
$b = microtime(1);
memoryUsage(memory_get_usage(), $base_memory_usage,' — потребление памяти при использовании финкций и глобальной переменной');
echo 'function: ',$b — $a;
echo "\n";
$base_memory_usage = memory_get_usage();
$a = microtime(1);
for ($q->c('i', 0); $q->r('i') < 1000000; $q->i('i')) {
$q->c('is', 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'.$q->r('i'));
}
apc_store('object q',$q);
$b = microtime(1);
memoryUsage(memory_get_usage(), $base_memory_usage,' — потребление памяти при использовании уже инициализированного оъекта');

echo 'object: ', $b — $a;
echo "\n";
$base_memory_usage = memory_get_usage();
$a = microtime(1);
for (apc_store('i', 0); apc_fetch('i') < 1000000; apc_inc('i')) {
apc_store('is', 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'.apc_fetch('i'));
}
$b = microtime(1);
memoryUsage(memory_get_usage(), $base_memory_usage,' — память внутри воркера не используется');
echo ':apc: ',$b — $a;

Тест возвращает вот такие результаты;
Разница использования памяти внутри скрипта в байтах: 224 - инициализация класса

Разница использования памяти внутри скрипта в байтах: 552 - потребление памяти при использовании функций и глобальной переменной
function: 4.7004411220551

Разница использования памяти внутри скрипта в байтах: 960 - потребление памяти при использовании уже инициализированного объекта
object: 4.1361658573151

Разница использования памяти внутри скрипта в байтах: 0 - память внутри воркера не используется
:apc: 3.9975609779358

Как видите сами скорость работы с памятью apc очень даже приемлемая и сопоставима с работой класса в php. Тут стоит передать привет классу APCIterator, который более продвинуто работает с локами, более быстро вытаскивает большие объемы данных, и может доставать переменные с подошью регулярок, которые кстати работают на уровне C.

Миф 3. В PHP каждый раз инициализируются объекты и по другому никак


apc_store(),apc_fetch(),apc_add()
Эта троица способна работать с объектами в том числе которые уже инициализированные. Однако класс объекта должен быть подгружен либо автоматический либо принудительно.
Проведем ряд тесов которые покажут, что из этого мы можем выжать:

Код
class q{   
public $i;
public $n;
    public function c($i, $e) {
    $this->i[$i]=$e;
}

   public function qq($i,$n) {
       $this->n=$n;
   return $this->qqq($i);
}

public function qqq($i) {
   $this->i[$i]=$this->i[$i] + $this->n;
   return $this->i[$i];
}

public function r($i) {    
    return  $this->i[$i];
}

public function i($i, $e = 1) {
 $this->i[$i]++;
}}
$q=new q();
$q->c('i',1000000);
apc_store('object q',$q);
$base_memory_usage = memory_get_usage();
print_r(apc_fetch('object q'));
memoryUsage(memory_get_usage(), $base_memory_usage,' - Смотрим на обьект до применения метода');
$base_memory_usage = memory_get_usage();
print_r(apc_fetch('object q')->qq('i',123));
memoryUsage(memory_get_usage(), $base_memory_usage,' - Достаем результат сразу применяя метод.');
$base_memory_usage = memory_get_usage();
print_r(apc_fetch('object q'));
memoryUsage(memory_get_usage(), $base_memory_usage,' - Смотрим на обьект после применения метода');
$base_memory_usage = memory_get_usage();
$new = apc_fetch('object q');
memoryUsage(memory_get_usage(), $base_memory_usage,' - Записываем объект в переменную для полноценно работы с обьектом');


Результат очень интересный:

q Object
(
    [i] => Array
        (
            [i] => 1000000
        )

    [n] => 
)

Разница использования памяти внутри скрипта в байтах: 0 - Смотрим на объект до применения метода
1000123
Разница использования памяти внутри скрипта в байтах: 128 - Достаем результат сразу применяя метод.
q Object
(
    [i] => Array
        (
            [i] => 1000000
        )

    [n] => 
)

Разница использования памяти внутри скрипта в байтах: 0 - Смотрим на объект после применения метода

Разница использования памяти внутри скрипта в байтах: 992 - Записываем в переменную для работы с объектом

Мы можем работать с уже инициализированными объектами, и более того мы можем сразу применить метод и получить ответ не используя лишнюю память. Насколько это практично может подсказать только реальное применение этой технологии.

Используя те или иные подходы можно сэкономить и память и процессорное время. Кроме того мы можем быстро обмениваться данными между воркерами, что позволяет PHP не отставать от асинхронных языков.