|
PHP / MySQL Создание динамических Веб-ресурсов |
27.09.2013, 00:59
|
#1
|
|
Странное поведение массива...
Реализовал класс хуков через типы - все работало отлично. Потом решил переделать с использованием массивов - четко видно, что нигде логического тупняка я не допустил, методы класса логгируют, что добавлены 2 функции... но почему-то при запуске хука вызывается только одна функция... не могу понять в чем тут фейл...,,,???
Исходный код с примером ->
На страницу должно вывести такую запись "Albert Hello! How are you?" но вторая функция не срабатывает и выводит только "Albert Hello!"
<?php class Hook { protected $_data = null; public function add($func, $context=null, $priority=0) { if (is_callable($func) == false) { return false; } $t = [$func, $context, $priority, null]; $pred = null; $hook = $this->_data; while ($hook != null) { if ($priority > $hook[2]) { break; } $pred = $hook; $hook = $hook[3]; } if ($pred != null) { $t[3] = $pred[3]; $pred[3] = $t; echo("add :".$func); } else { $t[3] = $this->_data; $this->_data = $t; echo("added ".$func); } return true; } public function run($data=null) { $hook = $this->_data; while ($hook != null) { echo($hook[0]); $data = call_user_func($hook[0], $data, $hook[1]); $hook = $hook[3]; } return $data; } public function rem($func, $context=null) { $pred = null; $hook = $this->_data; while (($hook != null) and (($hook[0] != $func) or ($hook[1] != $context))) { $pred = $hook; $hook = $hook[3]; } if ($hook == null) { return false; } if ($pred != null) { $pred[3] = $hook[3]; } else { $this->_data = $hook[3]; } return true; } }; /* ***EXAMPLE*** */ function test1($data, $context) { return $data.' Hello!'; } function test2($data, $context) { return $data.' How are you?'; } $hook = new Hook; $hook->add('test1'); $hook->add('test2'); echo($hook->run('Albert')); $hook = null; ?>
|
|
|
27.09.2013, 09:44
|
#2
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Странное поведение массива...
Вероятно потому что при присвоении создается копия массива?
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
27.09.2013, 10:16
|
#3
|
|
Ответ: Странное поведение массива...
Не знал про такую особенность.
работающий код ->
<?php
class Hook { protected $_data = null; public function add($func, $context=null, $priority=0) { if (is_callable($func) == false) { return false; } $t = [$func, $context, $priority, null]; $pred = null; $hook = &$this->_data; while ($hook != null) { if ($priority > $hook[2]) { break; } $pred = &$hook; $hook = &$hook[3]; } if ($pred != null) { $t[3] = &$pred[3]; $pred[3] = &$t; } else { $t[3] = &$this->_data; $this->_data = &$t; } return true; } public function run($data=null) { $hook = &$this->_data; while ($hook != null) { $data = call_user_func($hook[0], $data, $hook[1]); $hook = &$hook[3]; } return $data; } public function rem($func, $context=null) { $pred = null; $hook = &$this->_data; while (($hook != null) and (($hook[0] != $func) or ($hook[1] != $context))) { $pred = &$hook; $hook = &$hook[3]; } if ($hook == null) { return false; } if ($pred != null) { $pred[3] = &$hook[3]; } else { $this->_data = &$hook[3]; } return true; }
};
/* ***EXAMPLE*** */
function test1($data, $context) { return $data.' Hello!'; }
function test2($data, $context) { return $data.' How are you?'; }
$hook = new Hook;
$hook->add('test1'); $hook->add('test2'); echo($hook->run('Albert')); $hook = null;
?>
|
|
|
28.09.2013, 07:01
|
#4
|
Элита
Регистрация: 14.06.2008
Адрес: Украина, Киев
Сообщений: 2,273
Написано 754 полезных сообщений (для 1,833 пользователей)
|
Ответ: Странное поведение массива...
Добавлю, что в PHP копия массива в памяти создаётся только при изменении одного из них. То есть допустим мы создали массив, присвоили его ещё десяти переменным (не по ссылке & !), в памяти этот массив всё ещё хранится в одном экземпляре. Пока мы просто читаем данные из этих массивов, ничего не происходит, но как только мы захотим изменить массив какой-то из переменных, например, добавить новый элемент, то тогда создаётся отдельная копия массива в памяти.
Это я к тому, что не стоит для оптимизации писать $newArray=&$array;
Использовать ссылку нужно только тогда, когда нужно именно такое поведение.
|
(Offline)
|
|
28.09.2013, 07:21
|
#5
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Странное поведение массива...
Тут пишут что всегда копирование:
http://php.net/manual/ru/language.types.array.php
Обратите внимание, что при присваивании массива всегда происходит копирование значения. Чтобы скопировать массив по ссылке, вам нужно использовать оператор ссылки.
|
|
(Offline)
|
|
28.09.2013, 08:08
|
#6
|
Элита
Регистрация: 14.06.2008
Адрес: Украина, Киев
Сообщений: 2,273
Написано 754 полезных сообщений (для 1,833 пользователей)
|
Ответ: Странное поведение массива...
С уровня абстракции языка так оно и есть, но в памяти интерпретатора оба массива будут храниться как один. Но как только ты в один из массивов добавишь новый элемент, интерпретатор сразу создаст копию массива для второй переменной и только тогда добавит туда новый элемент.
Например, нужно написать функцию, которая будет получать массив чисел и возвращать сумму всех этих чисел. Причём мы планируем использовать функцию для очень больших массивов, занимающих много оперативной памяти.
Сначала программист напишет так:
function ololoSum($array){ $sum=0; $length=count($array); for($i=0;$i<$length;$i++){ $sum+=$array[$i]; } return $sum; }
Потом прочитает в мануале:
Обратите внимание, что при присваивании массива всегда происходит копирование значения. Чтобы скопировать массив по ссылке, вам нужно использовать оператор ссылки.
|
И перепишет так (чтобы массив в функцию передавался по ссылке):
function ololoSum(&$array){ $sum=0; $length=count($array); for($i=0;$i<$length;$i++){ $sum+=$array[$i]; } return $sum; }
Программист будет думать, что при передаче массива в первый вариант функции будет создана копия массива (мы же не по ссылке передаём и имеем дело с локальной копией массива) и на момент вызова функции вместо 100500 килобайт занятой оперативы у нас получится 100500*2. Нихера не так. Под локальную копию массива не будет выделена новая память на содержимое массива. Вместо этого интерпретатор внутри себя будет ссылаться на ту же самую память глобально созданного массива. То есть на деле оба варианта функции будут работать примерно одинаково и не приведут к излишнему расходу памяти. Но если внутри первой функции мы напишем в каком-то месте, например, $array[0]=0; , то в этом месте интерпретатор создаст полную копию массива и только тогда изменит в нём нулевую ячейку. Вот тогда выделение памяти будет 100500*2.
|
(Offline)
|
|
Эти 3 пользователя(ей) сказали Спасибо Phantom за это полезное сообщение:
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 12:01.
|