forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   PHP / MySQL (http://forum.boolean.name/forumdisplay.php?f=135)
-   -   Странное поведение массива... (http://forum.boolean.name/showthread.php?t=18569)

Черный крыс 27.09.2013 00:59

Странное поведение массива...
 
Реализовал класс хуков через типы - все работало отлично. Потом решил переделать с использованием массивов - четко видно, что нигде логического тупняка я не допустил, методы класса логгируют, что добавлены 2 функции... но почему-то при запуске хука вызывается только одна функция... не могу понять в чем тут фейл...,,,???

Исходный код с примером ->

На страницу должно вывести такую запись "Albert Hello! How are you?" но вторая функция не срабатывает и выводит только "Albert Hello!"

PHP код:

<?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;

?>


pax 27.09.2013 09:44

Ответ: Странное поведение массива...
 
Вероятно потому что при присвоении создается копия массива?
PHP код:

$pred = &$hook


Черный крыс 27.09.2013 10:16

Ответ: Странное поведение массива...
 
Не знал про такую особенность.

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

PHP код:

<?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;



?>


Phantom 28.09.2013 07:01

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

Это я к тому, что не стоит для оптимизации писать $newArray=&$array;
Использовать ссылку нужно только тогда, когда нужно именно такое поведение.

pax 28.09.2013 07:21

Ответ: Странное поведение массива...
 
Тут пишут что всегда копирование:
http://php.net/manual/ru/language.types.array.php
Цитата:

Обратите внимание, что при присваивании массива всегда происходит копирование значения. Чтобы скопировать массив по ссылке, вам нужно использовать оператор ссылки.

Phantom 28.09.2013 08:08

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

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

Сначала программист напишет так:
PHP код:

function ololoSum($array){
  
$sum=0;
  
$length=count($array);
  for(
$i=0;$i<$length;$i++){
    
$sum+=$array[$i];
  }
  return 
$sum;


Потом прочитает в мануале:
Цитата:

Обратите внимание, что при присваивании массива всегда происходит копирование значения. Чтобы скопировать массив по ссылке, вам нужно использовать оператор ссылки.
И перепишет так (чтобы массив в функцию передавался по ссылке):
PHP код:

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.


Часовой пояс GMT +4, время: 15:38.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot