Проблема с презагрузкой магических методов

Slam

Новичок
Здравсвтуйте, возникла проблема при использовании методов __set() и __get()
Помогите, пожалуйста разобраться в чем проблема.
Итак есть код:
PHP:
class Some_Class 
{
    private $obj;
    
    public function __construct()
    {
    	$this->obj = array();
    }
   
    public function __set($name, $value)
    {
    	$this->obj[$name] = $value;
    	return true;
    }

    public function __get($name)
    {
     	if (array_key_exists($name, $this->auth)) {
            return $this->obj[$name];
        }
        else {
        	return null;
        }
    }
}
Далее:
PHP:
$some_object = new Some_Class();
$some_object = obj['Some']['Some2'] = 'Data';
И вот здесь возникает ошибка:
Notice: Indirect modification of overloaded property Some_Class ::$obj has no effect
Не могу понять где собака зарыта...
 

tony2001

TeaM PHPClub
ты, получается, пытаешься менять результат выполнения функции и ожидаешь, что поменяется переменная внутри этой функции.

в таком случае следует делать вот так:
public function &__get($name)
 

Вурдалак

Продвинутый новичок
Что-то я не понимаю: __set() и __get() создают видимость работы не с индексаторами, а со свойствами объекта. Как это связано с
PHP:
obj['Some']['Some2']
?
 

Slam

Новичок
Представим, что в конструкторе создается не пустой массив. Вот к его элементам и нужно получить доступ либо создать их и присвоить им значения.
Вот нашел сходную проблему: bugs.php.net
 

Духовность™

Продвинутый новичок
Если тебе нужно делать obj['Some']['Some2'], то используй ArrayAccess, но это не отменяет вопроса Вурдалака - как связано то? Моск включай и читай мануал до просветления.
 

Вурдалак

Продвинутый новичок
Он имел в виду что-то типа
PHP:
$some_object->obj['Some']['Some2'] = 'Data';
похоже. Совет tony2001 тут как раз к месту.

Ошибка
Notice: Only variable references should be returned by reference in Some_Class.php on line xxx
означает, что ты пытаешься вернуть значение (NULL, к примеру, как в твоём коде). Так нельзя. Ты говоришь, что если переменной нет, её нужно создать — вот и создавай и возвращай её, а не NULL.
 

Slam

Новичок
Согласен, ArrayAccess здесь больше подходит. Спасибо.
Попутно возник вопрос, хочу сразу в методе offsetSet() изменить значение переменной сессии, скажем вот так
PHP:
$_SESSION['test'] = $value;
Но это не дает эффекта. Что здесь не так?
 

Slam

Новичок
Потому что переменные сессии остаются такими же как и до установки значения для элемента массива. Мне тоже странно.
PHP:
public function offsetSet($offset, $value) 
	{
         $_SESSION['XXX'] = $value; // Ничего не изменяется!
        if (is_null($offset)) {
            $this->container[] = $value;
            
        } else {
            $this->container[$offset] = $value;
        }
    }
 

Slam

Новичок
Знаю, что глобальный.
Код копирнул из мана чтобы проверить. Он же работоспособный.
Наверное нужно спать ложиться, а то мозг уже не работает...
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Slam
так, как ты пишешь, писать не надо, надо использовать стандартные средства
опиши свою реальную задачу и люди подскажут, как лучше ее реализовать
 

Slam

Новичок
ок.
Есть класс реализующий аутентификацию пользователя. Соответственно в сессии хранится информация о пользователе. Хочется реализовать удобный способ работы.
PHP:
class Auth implements ArrayAccess
{
    private $auth;
    
    public function __construct()
    {
    	$this->auth = array();
        if (!isset($_SESSION)) session_start();
        
        if (!isset($_SESSION['auth']['user']))              $_SESSION['auth']['user'] 				= '';
        if (!isset($_SESSION['auth']['user_ticket']))       $_SESSION['auth']['user_ticket'] 		= '';
        if (!isset($_SESSION['auth']['registered']))        $_SESSION['auth']['registered'] 		= '';
        if (!isset($_SESSION['auth']['privileges']))        $_SESSION['auth']['privileges'] 		= '';
        if (!isset($_SESSION['auth']['last_login_date']))   $_SESSION['auth']['last_login_date'] 	= '';
        if (!isset($_SESSION['auth']['last_login_host']))   $_SESSION['auth']['last_login_host'] 	= '';
        if (!isset($_SESSION['auth']['user_info']))            $_SESSION['auth']['user_info']		= array();
        
        // Индикаторы ошибок
        if (!isset($_SESSION['errors']['auth'])) $this->clear_session_errors();
        
        foreach ($_SESSION['auth'] as $k => $v) {
        	$this->auth[$k] = $v;
        }
    }
}
Далее, где-то в скрипте не хочу конкретизироваться на сесси и писать что-то вроде
PHP:
$_SESSION['auth']['user_info']['Id']
А хотелось бы работать с объектом следующим образом:
PHP:
$auth_obj = new Auth();
// Получать зачения следующим образом
$auth_obj->auth['user_info']['Id'];
// Устанавливать 
$auth_obj->auth['registered'] = 1;
Вот такая идея.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
это смешение объектов и массивов в одном вызове и подмена одного другим через магию - плохой стиль кодинга
в единичных случаях, таких, как конфиги фреймворков, такое используется, но их авторы знают, что делают,
а в классе приложения, как твой случай, так не делает никто
тебе лучше писать обычно:
$authObj->userInfo->id
где userInfo - класс, а id - его поле

в принципе, можешь глянуть yii, там это реализовано в паре мест, но основной способ обращения там $Obj->getFoo()->getBar(), как и везде
 

Духовность™

Продвинутый новичок
class Auth implements ArrayAccess
так не правильно. ArrayAccess - это тип фактически. Наследовать от такого типа можно лишь
в единичных случаях
Твой случай - точно не тот. Если хочется ООПшности - создай объект сессии, быть может даже на базе ArrayAccess и используй его в class Auth. Сам же Auth не должен быть подтипом, он должен быть индивидуальным классом..

Вообще, я бы посоветовал тебе так же как и grigori забить на желание пользоваться объектами как массивами. У меня был такой опыт, это приводит к гимору невообразимому.
 

Духовность™

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

PS класс Cover_MapItem вам не нужен, забыл удалить
 

Вложения

  • Like
Реакции: Slam
Сверху