Объект php внутри объекта, получая экземпляр объекта верхнего уровня
я пытаюсь выяснить, возможно ли получить доступ к экземпляру объекта с помощью объекта, который был создан в этом экземпляре объекта?
звучит странно, вот пример:
class mainclass < var $data; function __construct($data)< $this->data = $data; > function echodata()< echo $this->data; > function start($classname)< include $classname.'.php'; $inner = new $classname(); $inner->show(); > > $mainclass = new mainclass('maininfostuff'); $mainclass->start('innerclass'); //i want it to echo "maininfostuff"
class innerclass< function show()< mainclass->echodata();//the problem is here > >
Цель этого теста — заставить внутренний класс решить, запускать ли функцию эходанных основного класса
Как можно выполнить приведенный выше пример? (без использования статических классов, синглетонов или расширенных классов)
редактировать: из-за путаницы в ответах я отредактировал пример
9 ответов
Внутренние занятия невозможны в PHP. Таким образом, вы не можете объявить свой внутренний класс в основном классе. А так как вы не можете этого сделать, нет способа получить доступ к переменным внешних классов, как, например, в Java.
Вы можете сделать это вместо этого:
class mainclass < var $data; function __construct($data)< $this->data = $data; > function echodata()< echo $this->data; > function start()< $inner = new innerclass(); $inner->show($this); > > class innerclass< function show($mainclass)< $mainclass->echodata();//the problem is here > > $mainclass = new mainclass('maininfostuff'); $mainclass->start();
Единственный способ для внутреннего класса иметь доступ к внешнему классу — это передать внешний экземпляр конструктору внутреннего класса и сохранить его в переменной экземпляра.
Лично я никогда не видел класс, определенный внутри методов другого класса, поэтому, если он вообще работает, я очень удивлен. (Я даже больше удивлен тем, почему вы хотите / нуждаетесь в этом, но в любом случае. )
Просто передайте текущий (внешний) объект внутреннему объекту при его создании.
class InnerClass < var $outer; function __construct(&$outer) < $this->outer = $outer; > function someStuff() < $this->outer->doStuff(); > > $innerObj = new InnerClass($this);
Нет, внутренние предложения не в PHP.
«Функциональность уже доступна на других языках, но вопрос в том, нужна ли она в PHP. Краткий ответ — нет. С моделью исполнения PHP это еще больше замедлит и раздувает компиляцию PHP». — http://jacobsantos.com/2006/general/dont-advocate-subclasses/comment-page-1/
Нет. Когда вы создаете объект как член другого объекта:
$this->my_new_object = new classname(a,b,c);
Насколько мне известно, нет никакого способа получить доступ к родительскому элементу. При создании объекта вам необходимо будет передать ссылку на родительский элемент:
class innerclass()< private $parent; // Reference to the parent object function __construct(&$parent) < $this->parent = $parent; > function show()< $this->parent->echodata(); > >
Однако определение класса никогда не должно находиться в функции, даже если это возможно. Определения классов могут иметь иерархию — они могут расширять друг друга. Но это вызывается с помощью extends , Класс может extend другой. Их определение все еще рядом, они не вложены в код.
Я не знаю, что вы пытаетесь сделать, но, возможно, вы ищете расширение класса. В этом случае вы можете получить доступ к функциям и переменным, определенным в родительском элементе, используя parent ключевое слово:
это, однако, нечто принципиально отличное от того, что вы делаете сейчас.
Кажется, вы должны сделать:
class mainclass < var $data; function __construct($data)< $this->data = $data; > function echodata()< echo $this->data; > function start()< class innerclass()< var $mainclass; function __construct($mainclass) < $this->mainclass = $mainclass; > function show()< $this->mainclass->echodata();//the problem is here > > $inner = new innerclass($this); $inner->show(); > > $mainclass = new mainclass('maininfostuff'); $mainclass->start();
Но, похоже, вы не можете сделать это в PHP:
Fatal error: Class declarations may not be nested in test.php on line 11
Так что извлеките свой внутренний класс из основного класса.
Позвольте мне обратиться к одной важной строке:
mainclass->echodata();//the problem is here
В PHP, чтобы использовать инфиксный оператор доступа к объектам ( -> ) левый аргумент должен быть переменной (с предшествующим хотя бы одним $ ) и должен быть экземпляром класса, например $myClass->whatever или же $this->foo ,
Если вы переходите с другого языка и думаете о статическом доступе, вы должны использовать правильный оператор, который :: например, someClass::$someValue или же someClass::SOME_CONST ,
Теперь, если вы категорически против передачи «родительского» объекта дочернему конструктору, вы можете рассмотреть шаблон синглтона, который позволит вам статически получить доступ к (единственному) экземпляру родительского класса из любой точки кода, включая дочерний объект.
А если серьезно, просто передайте его в качестве аргумента конструктору, и, как сказал кто-то другой, не определяйте класс внутри функции, особенно если эта функция сама является членом другого класса. Если эта функция вызывается дважды, вы получите фатальную ошибку.
РЕДАКТИРОВАТЬ
Вот пример того, о чем я говорю:
class mainClass < private static $instance = null; private $data = null; private function __construct($setData) < if (!is_null($setData)) < $this->data = $setData; > > public static function getInstance($setData = null) < if (is_null(self::$instance)) < self::$instance = new mainClass($setData); >return self::$instance; // objects will always be passed by reference > public function echodata() < echo $this->data; > public function start() < $inner = new innerClass; $inner->show(); > > class innerClass < function show() < mainClass::getInstance()->echodata(); > >
$foo = mainClass::getInstance('Foo'); $foo->start(); // prints "Foo"
Я нашел больше способов сделать это
class innerclass < function show()< mainclass::echodata(); >> class mainclass < var $data; protected static $_instance; function __construct($data)< $this->data = $data; self::$_instance = $this; > //run previosuly declared mainclass method from anywhere public static function echodata() < if( self::$_instance === NULL ) < self::$_instance = new self(); >self::$_instance->runechodata(); > function runechodata()< echo $this->data; > function start($classname)< $inner = new $classname(); $inner->show(); > > $mainclass = new mainclass('maininfostuff'); $mainclass->start('innerclass'); //i want it to echo "maininfostuff"
и этот тоже, который я предпочитаю, учитывая его довольно опрятный.
class sharing < protected static $mainclass; function echodata()< self::$mainclass->echodata(); > > class innerclass extends sharing < function show()< parent::echodata(); >> class mainclass extends sharing < var $data; function __construct($data)< $this->data = $data; parent::$mainclass = $this;//share $this > function echodata()< echo $this->data; > function start($classname)< $inner = new $classname(); $inner->show(); > > $mainclass = new mainclass('maininfostuff'); $mainclass->start('innerclass');
и вот класс совместного использования экземпляра объекта, который я только что сделал:)
//PHP Object Sharing class sharing < //list the classes that you would like to be available for sharing protected static $mainclass; //run any function that is shared (part of any of the shared objects) public function __call($name,$args)< $shared_objects = get_class_vars(get_class()); foreach($shared_objects as $sharedObject)< if (method_exists($sharedObject,$name))< $classname = get_class($sharedObject); self::$$classname->$name(implode(', ',$args)); return; > > > > class innerclass extends sharing < function show()< $data = 'inner says hi'; parent::echodata($data); >> class mainclass extends sharing < var $data; function __construct($data)< $this->data = $data; parent::$mainclass = $this;//share mainclass with anything that is a part of sharing > function echodata($moredata=NULL)< echo $this->data.'+'.$moredata; > function start($classname)< $inner = new $classname(); $inner->show(); > > $mainclass = new mainclass('maininfostuff'); $mainclass->start('innerclass'); //returns "maininfostuff+inner says hi"
это позволяет вам запускать любые общие функции «экземпляра объекта» из любого общего объекта. Теперь основной класс может включать / запускать любой внутренний класс, который ему нужен, в то время как внутренний класс имеет возможность запускать функции экземпляра основного класса, как если бы это уже был запущенный объект основного класса.
Использование классов внутри других классов
Бывает такое, что мы хотели бы использовать методы одного класса внутри другого, но не хотели бы наследовать от этого класса.
Почему мы не хотим наследовать?
Во-первых, используемый класс может являться вспомогательным и по логике нашего кода может не подходить на роль родителя.
Во-вторых, мы можем захотеть использовать несколько классов внутри другого класса, а с наследованием это не получится, ведь в PHP у класса может быть только один родитель.
Давайте посмотрим на практическом примере. Пусть у нас дан следующий класс Arr , в объект которого мы можем добавлять числа с помощью метода add :
Давайте теперь добавим в наш класс метод, который будет находить сумму квадратов элементов и прибавлять к ней сумму кубов элементов.
Пусть у нас уже существует класс SumHelper , имеющий методы для нахождения сумм элементов массивов:
Логично будет не реализовывать нужные нам методы еще раз в классе Arr , а воспользоваться методами класса SumHelper внутри класса Arr .
Для этого в классе Arr внутри конструктора создадим объект класса SumHelper и запишем его в свойство sumHelper :
Теперь внутри Arr доступно свойство $this->sumHelper , в котором хранится объект класса SumHelper с его публичными методами и свойствами (если бы публичные свойства были, сейчас их там нет, только публичные методы).
Создадим теперь в классе Arr метод getSum23 , который будет находить сумму квадратов элементов и прибавлять к ней сумму кубов элементов, используя методы класса SumHelper :
sumHelper = new SumHelper; > // Находим сумму квадратов и кубов элементов массива: public function getSum23() < // Для краткости запишем $this->nums в переменную: $nums = $this->nums; // Найдем описанную сумму: return $this->sumHelper->getSum2($nums) + $this->sumHelper->getSum3($nums); > public function add($number) < $this->nums[] = $number; > > ?>?php>
Давайте воспользуемся созданным классом Arr :
add(1); // добавляем в массив число 1 $arr->add(2); // добавляем в массив число 2 $arr->add(3); // добавляем в массив число 3 // Находим сумму квадратов и кубов: echo $arr->getSum23(); ?>?php>
Самостоятельно повторите описанные мною классы Arr и SumHelper .
Создайте класс AvgHelper с методом getAvg , который параметром будет принимать массив и возвращать среднее арифметическое этого массива (сумма элементов делить на количество).
Добавьте в класс AvgHelper еще и метод getMeanSquare , который параметром будет принимать массив и возвращать среднее квадратичное этого массива (квадратный корень, извлеченный из суммы квадратов элементов, деленной на количество).
Добавьте в класс Arr метод getAvgMeanSum , который будет находить сумму среднего арифметического и среднего квадратичного из массива $this->nums .
Использование классов внутри других классов
Бывает такое, что мы хотели бы использовать методы одного класса внутри другого, но не хотели бы наследовать от этого класса.
Почему мы не хотим наследовать?
Во-первых, используемый класс может являться вспомогательным и по логике нашего кода может не подходить на роль родителя.
Во-вторых, мы можем захотеть использовать несколько классов внутри другого класса, а с наследованием это не получится, ведь в PHP у класса может быть только один родитель.
Давайте посмотрим на практическом примере. Пусть у нас дан следующий класс Arr , в объект которого мы можем добавлять числа с помощью метода add :
Давайте теперь добавим в наш класс метод, который будет находить сумму квадратов элементов и прибавлять к ней сумму кубов элементов.
Пусть у нас уже существует класс SumHelper , имеющий методы для нахождения сумм элементов массивов:
Логично будет не реализовывать нужные нам методы еще раз в классе Arr , а воспользоваться методами класса SumHelper внутри класса Arr .
Для этого в классе Arr внутри конструктора создадим объект класса SumHelper и запишем его в свойство sumHelper :
Теперь внутри Arr доступно свойство $this->sumHelper , в котором хранится объект класса SumHelper с его публичными методами и свойствами (если бы публичные свойства были, сейчас их там нет, только публичные методы).
Создадим теперь в классе Arr метод getSum23 , который будет находить сумму квадратов элементов и прибавлять к ней сумму кубов элементов, используя методы класса SumHelper :
sumHelper = new SumHelper; > // Находим сумму квадратов и кубов элементов массива: public function getSum23() < // Для краткости запишем $this->nums в переменную: $nums = $this->nums; // Найдем описанную сумму: return $this->sumHelper->getSum2($nums) + $this->sumHelper->getSum3($nums); > public function add($number) < $this->nums[] = $number; > > ?>?php>
Давайте воспользуемся созданным классом Arr :
add(1); // добавляем в массив число 1 $arr->add(2); // добавляем в массив число 2 $arr->add(3); // добавляем в массив число 3 // Находим сумму квадратов и кубов: echo $arr->getSum23(); ?>?php>
Самостоятельно повторите описанные мною классы Arr и SumHelper .
Создайте класс AvgHelper с методом getAvg , который параметром будет принимать массив и возвращать среднее арифметическое этого массива (сумма элементов делить на количество).
Добавьте в класс AvgHelper еще и метод getMeanSquare , который параметром будет принимать массив и возвращать среднее квадратичное этого массива (квадратный корень, извлеченный из суммы квадратов элементов, деленной на количество).
Добавьте в класс Arr метод getAvgMeanSum , который будет находить сумму среднего арифметического и среднего квадратичного из массива $this->nums .