<?php class Primary { public $var='какая-то переменная'; public function __construct() { $db=array(тут данные для соединения с БД); $this->Secondary = new Secondary; $this->Secondary->Load($this->var); $this->Third = new Third; $this->Third->Method1($db); } } ?>
Также есть второй класс:
КОД
<?php class Secondary { public function Load($var) { $dbname ='чему-то равно'; $var2 = $Primary->Third->Method2($dbname); } } ?>
И Ещё есть третий класс:
КОД
<?php class Third { public function Method1() { $this->mysqli = new mysqli($db['host'], $db['user'], $db['password'], $db['name']); } public function Method2($dbname) { return $this->mysqli->select_db($dbname); } } ?>
Каждый класс расположен в отдельном файле.
Пишет ошибку, Fatal error: Call to a member function Method2() on a non-object in [...тут путь... к файлу, содержащему Secondary Class ]. Конкретно PHP не понравилась строка $var2 = $Primary->Third->Method2($dbname); в Secondary...
У меня есть предчувствие, что вызываемый класс не может просто так обращаться к вызывающему его классу.
Подскажите, пожалуйста, почему так происходит, в чём моя ошибка и как можно решить данную проблему.
Сообщение отредактировал wizard993: May 11 2011, 21:17
<?php require_once 'class_primary.php'; $Primary = new Primary; ?>
В class_primary.php прописал автолоад остальных двух классов (secondary и third). Проблема всё та же... Если изменить код Secondary таким образом:
КОД
<?php class Secondary { public function Load($var) { $dbname ='чему-то равно'; $Primary = new Primary; $var2 = $Primary->Third->Method2($dbname); } } ?>
или таким:
КОД
<?php class Secondary { public function Load($var) { $dbname ='чему-то равно'; $this->Primary = new Primary; $var2 = $this->Primary->Third->Method2($dbname); } } ?>
То появляется другой разряд ошибок: Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 261904 bytes) in [и тут любой из предложенных классов на выбор] Ошибка выскакивает после 10-секундного зацикливания и думанья браузера. Цифры в ошибке всегда разные... И останавливается на произвольном участке кода.
Сообщение отредактировал wizard993: May 11 2011, 21:18
в этом случае класс Primary надо делать статическим. и обращаться в нему через его статические методы. А так, как описано у тебя просто происходит переполнение памяти, так как первый класс вызывает конструктор второго а второй опять конструирует объект первого и опять и опять все повторяется.
vitalik1972, Вас 1 раз(а) поблагодарили за это сообщение:
Тогда ещё такой вопрос. Допустим, у меня много файлов с классами. Неужели необходимо в каждом прописывать что-то вроде $this->Primary = Primary::Primary(); Есть ли какое-нибудь решение такой ситуации?
Это не надо писать. К статическому классу можно обращаться по его имени из любого места.
vitalik1972, Немножко не понимаю. Из того, что я читал по PHP есть такие понятия, как статические члены класса и статические методы класса. К ним идёт обращение через оператор разрешения области видимости ( : : ) А как выглядит такое чудо, как статический класс? На php.net вроде не нашёл... Не могли бы показать на небольшом примере, что он из себя представляет и как к нему обращаться? P.S. пробежался по форумам. Я так понял статический класс - это класс, у которого все свойства и методы - статические? Поправьте, если не так. P.P.S тогда в связи с этим ещё вопрос. А можно ли в моём случае, не делать весь класс статическим, а создать какой-нибудь статический метод, который создаёт объект этого класса; и потом обращаться из других классов к нему посредством оператора разрешения области видимости. Вот ниже код того, что я хочу сказать (IMG:http://antislaed.net/style_emoticons/default/smile.gif)
КОД
<?php class Primary { public $var='какая-то переменная'; public $static_var; public function __construct() { $db=array(тут данные для соединения с БД); $this->Secondary = new Secondary; $this->Secondary->Load($this->var); $this->Third = new Third; $this->Third->Method1($db); } public static function static_method() { self::$static_var=new self(); return self::$static_var; } } ?>
Обращаться к нему так:
КОД
<?php class Secondary { public function Load($var) { $dbname ='чему-то равно'; $this->Primary = Primary::static_method(); $var2 = $Primary->Third->Method2($dbname); } } ?>
Ошибка та же, связана с памятью. И всё равно приходится в каждом классе, подключаемом из автолоада прописывать $this->Primary = Primary::static_method();
ЦИТАТА(vitalik1972 @ May 12 2011, 08:15 )
Либо как вариант, пусть все твои классы происходят от одного класса родителя, в котором есть определение нужного тебе статического класса.
То есть, Вы имеете ввиду, что допустим, класс Primary родительский, а остальные наследуются от него?
КОД
class Secondary extends Primary { //... }
Прикрепил файлы.
Сообщение отредактировал wizard993: May 12 2011, 09:21
То есть, Вы имеете ввиду, что допустим, класс Primary родительский, а остальные наследуются от него?
Нет. Давай я лучше на примере KiVi CMS покажу как реализован статический класс и происходит обращение к нему: Итак, существует статический класс CApp (от слов Класс Приложение) сам он происходит от статического класса CBaseApp (зачем сделано так, здесь обсуждать не будем) Код файла index.php в корне сайта:
public static function init() { self::$app = new CApp (); return self::$app; }
Все методы этого класса статические, поэтому все обращения к вызову класса приложения происходят через :: То есть, чтобы вызвать какую либо функцию данного класса или переменную обращаемся так: (например запрос к БД) $res = CApp::$db->sql_query("тут код запроса");
Скачай с оффсайта киви последний релиз и покопайся в коде, я уверен, что ты легко в нем разберешься.
А проблемы с памятью потому, что как только ты делаешь new у тебя вызывается конструктор этого класса, который порождает второй и третий классы, которые порождают первый и так далее. Вот именно поэтому я использую функцию init для инициализации класса и вызываю этот метод сего 1 раз.
Сообщение отредактировал vitalik1972: May 12 2011, 21:03
vitalik1972, Вас 1 раз(а) поблагодарили за это сообщение:
То есть индекс обращается к статическому методу getInstance() класса Mainclass
!!! НО если открыть файл classes\mainclass.php , то в структуре самого класса Mainclass можно увидеть не только статические методы, например, public function LoadService(). То есть класс Mainclass не является статическим, если я правильно понимаю...
Далее, частично рассмотрим статическую функцию getInstance()
Если я опять же правильно понял, функция возвращает объект класса Mainclass, в том случае, если он не был создан. Обращение конкретно такого вида: $Mainclass=Mainclass::getInstance(); я заметил только в index.php. В других файлах иногда встречаются конструкции вида Mainclass::$Instance->name_of_some_object_or_method, но опять же не везде.
Встречаются файлы, где какого-либо видимого создания объекта класса Mainclass вообще нету. То есть идут несколько строчек кода, никак не относящиеся к Mainclass, а потом сразу без "привета" идёт строка что-то вроде return $this->Mainclass->SCookie($c_name,$value);
Вот мне и интересно как добиться такой реализации...
В элеаноре getInstace в киви Init, разницы никакой нет. В элеаноре есть проверка на "дурака", то есть на повторный вызов
КОД
if(!isset(self::$Instance))
в киви ее нет, посчитал ненужной, да собственно так и продолжаю думать. Объясни смысл не полностью статического класса? В любом случае это объект, а статическая функция или нет я например не вижу разницы в данном контексте. Может быть санвас пояснит свой код? Давай подождем его комментариев...
ЦИТАТА
Встречаются файлы, где какого-либо видимого создания объекта класса Mainclass вообще нету.
Я наконец-то понял, что ты имеешь в виду (IMG:http://antislaed.net/style_emoticons/default/smile.gif) Вобщем я могу сказать тебе так: если есть хотя бы одна статическая функция или переменная в классе - то он будет статическим. Статический - это говорит о том, что в памяти в процессе исполнения может быть всего лишь 1 объект данного класса. Надеюсь, что прояснил ситуацию
Сообщение отредактировал vitalik1972: May 13 2011, 07:36
vitalik1972, Вас 1 раз(а) поблагодарили за это сообщение:
Статический - это говорит о том, что в памяти в процессе исполнения может быть всего лишь 1 объект данного класса. Надеюсь, что прояснил ситуацию
Да, прояснил. А то про static довольно мало в книгах написано.
Из литературы читал, что когда свойство или метод помечают ключевым словом static, то можно к ним обращаться без создания объекта класса и с помощью оператора :: . Ещё, знаю, что для всех объектов класса, статические свойства и методы являются общими. (То есть, если изменяются в одном объекте, то изменяются и в другом объекте). А есть ещё какие-нибудь принципиальные различия между статическими членами и обычными? И какие "+" и "-" есть в использовании?
Ну вот например смотри: Ты создаешь какое-либо приложение. Класс приложения будет всего один, так почему бы его не сделать статическим? а вот классов блоков может быть несколько, соответственно они и должны быть динамическими. То же самое касается модулей и прочего. Тем более, что и обращение к статическому классу очень удобное через ::
Например пишешь какой либо модуль или блок и вызываешь класс приложения через CApp:: Мне кажется что так очень наглядно все происходит, код легкий получается, опять таки из кода хорошо видно, что вызываются "стандартные" методы приложения.
vitalik1972, Вас 1 раз(а) поблагодарили за это сообщение:
но меня всё равно гложет мысль о том, как же Sunvas реализовал это чудо в Элеаноре.
Возьмём начало файла classes\class_cache.php из Eleanor CMS (можно взять любой другой класс - это не важно)
КОД
class Cache extends BaseClass { public $langvars=array(), $Lib; public function Init() { $unique='elca_'; if(function_exists('apc_store') and file_exists($this->Mainclass->root_path.'classes/cache/class_cachemachine_apc.php'))
Вот что я не могу понять. Объект класса Mainclass не создаётся. Следовательно обращение к переменной root_path должно осуществляться через оператор :: Но, оно почему-то осуществляется так, КАК БУДТО СОЗДАН объект с именем Mainclass класса Mainclass.
Где искать разгадку? Мне интуиция говорит, что рыть надо где-то в mainclass.php. Но, к сожалению, сколько не пытался, ничего похожего на реализацию этого чуда не нашёл.
Народ, пожалуйста, объясните, каким образом так происходит? За счёт какой функции или чего-нибудь ещё?
Сообщение отредактировал wizard993: May 16 2011, 20:38
Класс MainClass реализует шаблон проектирования Singleton (всегда создается не более одного объекта этого класса)
КОД
$Mainclass = MainClass::getInstance();
возвращает объект класса (всегда один и тот же) - к нему можно обращаться как к любому другому объекту (->) статические методы по прежнему доступны через :: статические методы не наследуются, но их можно переопределить.
вместо этого кода можно было бы использовать
КОД
$Mainclass = new MainClass();
но тогда нет гарантии, что не появится еще один объект ГлавныйКласс ))
ЦИТАТА
Вот что я не могу понять. Объект класса Mainclass не создаётся. Следовательно обращение к переменной root_path должно осуществляться через оператор :: Но, оно почему-то осуществляется так, КАК БУДТО СОЗДАН объект с именем Mainclass класса Mainclass.
Этот объект может создаваться в родительском классе и использоваться в дочернем.
Сообщение отредактировал patriot: May 22 2011, 17:40
patriot, Вас 1 раз(а) поблагодарили за это сообщение: