Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   www.boolean.name > Веб-программирование > PHP / MySQL

PHP / MySQL Создание динамических Веб-ресурсов

Ответ
 
Опции темы
Старый 26.09.2013, 20:59   #1
Черный крыс
 
Сообщений: n/a
Странное поведение массива...

Реализовал класс хуков через типы - все работало отлично. Потом решил переделать с использованием массивов - четко видно, что нигде логического тупняка я не допустил, методы класса логгируют, что добавлены 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$prioritynull];
        
        
$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, 05:44   #2
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,502
Написано 2,957 полезных сообщений
(для 5,222 пользователей)
Ответ: Странное поведение массива...

Вероятно потому что при присвоении создается копия массива?
$pred = &$hook
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Черный крыс (27.09.2013)
Старый 27.09.2013, 06:16   #3
Черный крыс
 
Сообщений: n/a
Ответ: Странное поведение массива...

Не знал про такую особенность.

работающий код ->

<?php

class Hook {
    
    protected 
$_data null;
    
    public function 
add($func$context=null$priority=0) {
        
        if (
is_callable($func) == false) { return false; }
        
        
$t = [$func$context$prioritynull];
        
        
$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, 03:01   #4
Phantom
Элита
 
Аватар для Phantom
 
Регистрация: 14.06.2008
Адрес: Украина, Киев
Сообщений: 2,130
Написано 697 полезных сообщений
(для 1,731 пользователей)
Ответ: Странное поведение массива...

Добавлю, что в PHP копия массива в памяти создаётся только при изменении одного из них. То есть допустим мы создали массив, присвоили его ещё десяти переменным (не по ссылке & !), в памяти этот массив всё ещё хранится в одном экземпляре. Пока мы просто читаем данные из этих массивов, ничего не происходит, но как только мы захотим изменить массив какой-то из переменных, например, добавить новый элемент, то тогда создаётся отдельная копия массива в памяти.

Это я к тому, что не стоит для оптимизации писать $newArray=&$array;
Использовать ссылку нужно только тогда, когда нужно именно такое поведение.
(Offline)
 
Ответить с цитированием
Старый 28.09.2013, 03:21   #5
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,502
Написано 2,957 полезных сообщений
(для 5,222 пользователей)
Ответ: Странное поведение массива...

Тут пишут что всегда копирование:
http://php.net/manual/ru/language.types.array.php
Обратите внимание, что при присваивании массива всегда происходит копирование значения. Чтобы скопировать массив по ссылке, вам нужно использовать оператор ссылки.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 28.09.2013, 04:08   #6
Phantom
Элита
 
Аватар для Phantom
 
Регистрация: 14.06.2008
Адрес: Украина, Киев
Сообщений: 2,130
Написано 697 полезных сообщений
(для 1,731 пользователей)
Ответ: Странное поведение массива...

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

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

Сначала программист напишет так:
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 за это полезное сообщение:
moka (28.09.2013), pax (28.09.2013), Черный крыс (28.09.2013)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +1, время: 09:32.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com