«Не удалось выполнить Model_Hotel :: __ construct ()» с mysql_fetch_object, свойства остаются неинициализированными - PullRequest
2 голосов
/ 23 июля 2011

Я использую PHP 5.3.6 с MAMP 2.0.1 на Mac OS X Lion и использую Kohana 3.1.3.1.

Я пытаюсь переопределить методы __set () и __get () стандартного модуля Kohana ORM своими собственными методами. Некоторые из моих моделей расширяют мой класс, который расширяет класс ORM.

<?php

class ORM_Localization extends ORM
{

    protected static $_language_cache = array();
    protected $_languages = array();

    public function __construct($id = NULL)
    {
        parent::__construct($id);

        // Load languages which are accepted by the client
        $this->_languages = array_keys(Application::languages());
    }

    public function __get($name)
    {
        /* Debugging #1 */ echo 'GET'.$name;
        /* Debugging #2 */ // exit;
        return $this->localization($name);
    }

    public function __set($name, $value)
    {
        /* Debugging #3 */ var_dump($this->_table_columns);
        /* Debugging #4 */ echo 'SET::'.$name;
        /* Debugging #5 */ // exit;
        $this->localization($name, $value);
    }

    public function localization($name, $value = NULL)
    {
        if (!array_key_exists($name, $this->_table_columns)) {
            // Load avaiable languages from database if not already done
            if (empty(ORM_Localization::$_language_cache)) {
                ORM_Localization::$_language_cache = ORM::factory('languages')
                    ->find_all()
                    ->as_array('id', 'identifier');
            }

            $languages = array();

            // Find the IDs of the languages from the database which match the given language
            foreach ($this->languages as $language) {
                $parts = explode('-', $language);

                do {
                    $identifier = implode('-', $parts);

                    if ($id = array_search($identifier, ORM_Localization::$_language_cache)) {
                        $languages[] = $id;
                    }

                    array_pop($parts);
                } while($parts);
            }

            // Find localization
            foreach ($languages as $language) {
                $localization = $this->localizations->where('language_id', '=', $language)->find();

                try {
                    if ($value === NULL) {
                        return $localization->$name;
                    } else {
                        $localization->$name = $value;
                    }
                } catch (Kohana_Exception $exception) {}
            }
        }

        if ($value === NULL) {
            return parent::__get($name);
        } else {
            parent::__set($name, $value);
        }
    }

}

Но в PHP 5.3.6 я получаю следующее сообщение об ошибке:

Исключение [0]: не удалось выполнить Model_Hotel :: __ construct ()

Model_Hotel расширяет этот класс и не имеет собственной конструкции. Это код Model_Hotel, стандартной модели Kohana ORM: http://pastie.org/private/vuyig90phwqr9f34crwg

С PHP 5.2.17 я получаю еще один:

ErrorException [Предупреждение]: array_key_exists () [function.array-key-существующие]]: вторым аргументом должен быть либо массив, либо объект

В Kohana моя модель, которая расширяет мой класс, вызывается mysql_fetch_object (), где-то глубоко в коде модулей orm.

Тем не менее, если после этого я вызову вызываемое свойство в __set () и выйду (# 4 и # 5), он выдаст «SET :: id» и не отобразит сообщение об ошибке.

Если я var_dump () $ this -> _ table_columns (или любое другое свойство этого класса, # 3), я получу «NULL», то есть значение, которое имеет это свойство до его инициализации. Если я повторю то же самое с $ this -> _ languages, я получу пустой массив, который должен быть заполнен несколькими языками. Как будто класс никогда не инициализировался с __construct. Это объясняет ошибку, которую я получаю в PHP 5.2.17, потому что $ this -> _ table_columns имеет значение NULL, а не массив.

Я могу раскомментировать свою __construct, и все равно получаю ту же ошибку, ошибка должна быть в моем методе localization ().

Я искал несколько дней, и я понятия не имею, что может быть не так.

Ответы [ 3 ]

3 голосов
/ 23 июля 2011
Ожидается, что

ORM::__set() загрузит данные приведения из вызова mysql_fetch_object(). Вы должны позволить ему установить приведенное значение по этой причине:

public function __set($column, $value)
{
    if ( ! isset($this->_object_name))
    {
        // Object not yet constructed, so we're loading data from a database call cast
        $this->_cast_data[$column] = $value;
    }
    else
    {
        // Set the model's column to given value
        $this->localization($column, $value);
    }
}

Хотя это решение мне тоже не нравится, вместо этого вы должны переопределить ORM::set().

1 голос
/ 23 июля 2011

__construct() вызывается автоматически после инициализации объекта.

$class = new Object;
0 голосов
/ 09 апреля 2013

У меня есть немного больше информации по этому вопросу, так как я столкнулся с той же проблемой.

1) Я нашел сообщение об ошибке PHP, в котором говорится, что в mysqli и mysql_fetch_object __set () вызывается перед __construct (). Отчет за 2009 год предположительно был исправлен, но в версии 5.3, которую я использую, похоже, что это все еще происходит. Вот оно: https://bugs.php.net/bug.php?id=48487

2) Если в процессе выполнения вашего метода __set() вы выбросите исключение или возникнет какая-либо другая ошибка, вы получите это смутное сообщение «not call X::__construct()» вместо real исключение / сообщение об ошибке.

Я мог бы решить мою проблему таким образом:

public function __set($key, $val){
    if($constructor_has_not_run){
        $this->__construct();
    }

    //do stuff
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...