Вложенный класс в php

Вложенный или внутренний класс в PHP

Я знаю, что C ++ , Java и даже Ruby (и, возможно, другие языки программирования) позволяют вложенным / внутренним классам внутри основного класса, что позволяет сделать код более объектно-ориентированным и организованным.

В PHP я хотел бы сделать что-то вроде этого:

php public class User < public $userid; public $username; private $password; public class UserProfile < // Some code here >private class UserHistory < // Some code here >> ?> 

Возможно ли это в PHP? Как я могу это достичь?

Если это невозможно, будущие версии PHP могут поддерживать вложенные классы?

Solutions Collecting From Web of «Вложенный или внутренний класс в PHP»

Вступление:

Вложенные классы относятся к другим классам немного иначе, чем к внешним классам. Взятие Java в качестве примера:

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

OuterClass outerObj = new OuterClass(arguments); outerObj.InnerClass innerObj = outerObj.new InnerClass(arguments); 

Есть несколько веских причин для их использования:

Если класс полезен только для одного другого класса, тогда логично связать и вставить его в этот класс и сохранить вместе.

Рассмотрим два класса верхнего уровня: A и B, где B нуждается в доступе к членам A, которые в противном случае были бы объявлены частными. Скрывая класс B в классе A, члены A могут быть объявлены частными, а B может получить к ним доступ. Кроме того, сам Б можно скрывать от внешнего мира.

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

В PHP

Вы можете иметь подобное поведение в PHP без вложенных классов.

Если все, что вы хотите достичь, это структура / организация, так как Package.OuterClass.InnerClass, пространства имен PHP могут быть достаточными. Вы даже можете объявить несколько пространств имен в одном файле (хотя из-за стандартных функций автозагрузки это может быть нежелательно).

namespace; class OuterClass <> namespace OuterClass; class InnerClass <> Пространство namespace; class OuterClass <> namespace OuterClass; class InnerClass <> 

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

Определение класса «пакет»

namespace < class Package < /* protect constructor so that objects can't be instantiated from outside * Since all classes inherit from Package class, they can instantiate eachother * simulating protected InnerClasses */ protected function __construct() <>/* This magic method is called everytime an inaccessible method is called * (either by visibility contrains or it doesn't exist) * Here we are simulating shared protected methods across "package" classes * This method is inherited by all child classes of Package */ public function __call($method, $args) < //class name $class = get_class($this); /* we check if a method exists, if not we throw an exception * similar to the default error */ if (method_exists($this, $method)) < /* The method exists so now we want to know if the * caller is a child of our Package class. If not we throw an exception * Note: This is a kind of a dirty way of finding out who's * calling the method by using debug_backtrace and reflection */ $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); if (isset($trace[2])) < $ref = new ReflectionClass($trace[2]['class']); if ($ref->isSubclassOf(__CLASS__)) < return $this->$method($args); > > throw new \Exception("Call to private method $class::$method()"); > else < throw new \Exception("Call to undefined method $class::$method()"); >> > > 

Случай использования

namespace Package < class MyParent extends \Package < public $publicChild; protected $protectedChild; public function __construct() < //instantiate public child inside parent $this->publicChild = new \Package\MyParent\PublicChild(); //instantiate protected child inside parent $this->protectedChild = new \Package\MyParent\ProtectedChild(); > public function test() < echo "Call from parent ->"; $this->publicChild->protectedMethod(); $this->protectedChild->protectedMethod(); echo "
Siblings
"; $this->publicChild->callSibling($this->protectedChild); > > > namespace Package\MyParent < class PublicChild extends \Package < //Makes the constructor public, hence callable from outside public function __construct() <>protected function protectedMethod() < echo "I'm ".get_class($this)." protected method
"; > protected function callSibling($sibling) < echo "Call from " . get_class($this) . " ->"; $sibling->protectedMethod(); > > class ProtectedChild extends \Package < protected function protectedMethod() < echo "I'm ".get_class($this)." protected method
"; > protected function callSibling($sibling) < echo "Call from " . get_class($this) . " ->"; $sibling->protectedMethod(); > > >

тестирование

$parent = new Package\MyParent(); $parent->test(); $pubChild = new Package\MyParent\PublicChild();//create new public child (possible) $protChild = new Package\MyParent\ProtectedChild(); //create new protected child (ERROR) , $parent = new Package\MyParent(); $parent->test(); $pubChild = new Package\MyParent\PublicChild();//create new public child (possible) $protChild = new Package\MyParent\ProtectedChild(); //create new protected child (ERROR) 
Call from parent -> I'm Package protected method I'm Package protected method Siblings Call from Package -> I'm Package protected method Fatal error: Call to protected Package::__construct() from invalid context и Call from parent -> I'm Package protected method I'm Package protected method Siblings Call from Package -> I'm Package protected method Fatal error: Call to protected Package::__construct() from invalid context 

ЗАМЕТКА:

Я действительно не думаю, что попытка эмулировать innerClasses на PHP – такая хорошая идея. Я думаю, что код менее чист и читабельен. Кроме того, есть, вероятно, другие способы достижения аналогичных результатов с использованием хорошо налаженного шаблона, такого как шаблон Observer, Decorator ou COmposition. Иногда даже простого наследования достаточно.

В 2013 году для PHP 5.6 в качестве RFC были предложены реальные вложенные классы с public / protected / private доступностью, но не сделали этого (пока нет голосования, нет обновления с 2013 года по состоянию на 2016/12/29 ):

По крайней мере, анонимные классы превратились в PHP 7

Будущий масштаб

Изменения, сделанные этим патчем, означают, что вложенные классы легче реализовать (крошечным битом).

Итак, мы можем получить вложенные классы в какой-то будущей версии, но пока не решили.

Вы не можете сделать это на PHP. Тем не менее, есть функциональные способы достижения этого.

Для получения дополнительной информации, пожалуйста, проверьте этот пост: Как сделать PHP вложенный класс или вложенные методы?

Этот способ реализации называется свободным интерфейсом: http://en.wikipedia.org/wiki/Fluent_interface

Вы не можете сделать это в PHP. PHP поддерживает «include», но вы даже не можете сделать это внутри определения класса. Здесь не так много отличных вариантов.

Это не отвечает на ваш вопрос напрямую, но вы можете быть заинтересованы в «Пространства имен», ужасно уродливый \ syntax \ hacked \ on \ top \ PHP OOP: http://www.php.net/manual/en/language .namespaces.rationale.php

С PHP версии 5.4 вы можете принудительно создавать объекты с помощью частного конструктора посредством отражения. Его можно использовать для моделирования Java-вложенных классов. Пример кода:

class OuterClass < private $name; public function __construct($name) < $this->name = $name; > public function getName() < return $this->name; > public function forkInnerObject($name) < $class = new ReflectionClass('InnerClass'); $constructor = $class->getConstructor(); $constructor->setAccessible(true); $innerObject = $class->newInstanceWithoutConstructor(); // This method appeared in PHP 5.4 $constructor->invoke($innerObject, $this, $name); return $innerObject; > > class InnerClass < private $parentObject; private $name; private function __construct(OuterClass $parentObject, $name) < $this->parentObject = $parentObject; $this->name = $name; > public function getName() < return $this->name; > public function getParent() < return $this->parentObject; > > $outerObject = new OuterClass('This is an outer object'); //$innerObject = new InnerClass($outerObject, 'You cannot do it'); $innerObject = $outerObject->forkInnerObject('This is an inner object'); echo $innerObject->getName() . "\n"; echo $innerObject->getParent()->getName() . "\n"; 

Я думаю, что я написал элегантное решение этой проблемы, используя пространства имен. В моем случае внутреннему классу не нужно знать его родительский класс (например, статический внутренний класс в Java). В качестве примера я создал класс под названием «Пользователь» и подкласс «Тип», который использовался в качестве ссылки для пользовательских типов (ADMIN, OTHERS) в моем примере. С уважением.

User.php (файл пользовательского класса)

type;> public function setType($type)< $this->type = $type;> > > namespace User < class Type < const ADMIN = 0; const OTHERS = 1; >> ?> Пространство type;> public function setType($type)< $this->type = $type;> > > namespace User < class Type < const ADMIN = 0; const OTHERS = 1; >> ?> 

Using.php (пример того, как вызвать «подкласс»)

Согласно комментарию Ксенона к ответу Аниля Оззельгина, анонимные классы были реализованы в PHP 7.0, который находится как можно ближе к вложенным классам, так как вы получите прямо сейчас. Вот соответствующие RFC:

Вложенные классы (статус: снято)

Анонимные классы (статус: реализован в PHP 7.0)

Пример исходного сообщения, вот как выглядит ваш код:

profile = new class < // Some code here for user profile >$this->history = new class < // Some code here for user history >> > ?> 

Это, однако, идет с очень неприятным предостережением. Если вы используете среду IDE, такую ​​как PHPStorm или NetBeans, а затем добавьте такой метод в класс User :

public function foo() < $this->profile->. > 

… до свидания авто-пополнение. Это так, даже если вы кодируете интерфейсы (I в SOLID), используя такой шаблон:

profile = new class implements UserProfileInterface < // Some code here for user profile >> > ?> 

Если только ваши вызовы в $this->profile из метода __construct() (или любого $this->profile метода $this->profile определены в), то вы не получите какой-либо тип намека. Ваша собственность по сути «скрыта» для вашей среды разработки, что делает жизнь очень трудной, если вы полагаетесь на свою среду IDE для автоматического завершения, обнюхивания запаха кода и рефакторинга.

Поместите каждый класс в отдельные файлы и «потребуйте» их.

profile = new UserProfile(); $this->history = new UserHistory(); > > ?> 

Источник

PHP RFC: Nested Classes

Following on from anonymous classes, this RFC proposes we support nested classes in PHP.

Proposal

A nested class is a class declared in the virtual namespace of another class:

foo\bar is a nested class in the virtual namespace of foo .

A nested class has the ability to declare it’s accessibility to other classes in the same way as class members:

class foo { public class bar { } }

The first and second examples given here are therefore the same, by default classes are public, just like class members.

The following describes the functionality of access modifiers for nested classes:

Private Classes

The following example shows how to blackbox some of your functionality in a private nested class:

In the example \foo is the public facing API , \foo\bar contains supporting logic never to be exposed outside of \foo , any class declared in the virtual namespace \foo will be able to access the \foo\bar class.

Fatal error: Cannot access private class foo\bar from an unknown scope in %s on line %d

Private classes are very private, the following example demonstrates this:

 /* * foo * @package foo */ class foo { /* * foo\bar supporting class for foo * @subpackage foo\bar * @private */ private class bar { /* * \foo\bar\baz supporting class for foo\bar * @subpackage foo\bar\baz * @private */ private class baz { public function __construct() { } } public function __construct() { $this->baz = new foo\bar\baz(); } } /* PUBLIC API METHODS HERE */ public function __construct() { $this->bar = new \foo\bar(); $this->baz = new \foo\bar\baz(); /* line 39 */ } } new \foo(); ?>
Fatal error: Cannot access private class foo\bar\baz from foo in %s on line 39

Protecting bits of your Privates

The following example shows how protected and private classes can be used in conjunction to provide versatile encapsulation:

object(foo)#1 (2) < ["bar"]=>object(foo\bar)#2 (1) < ["baz"]=>object(foo\bar\baz)#3 (0) < >> ["baz"]=> object(foo\bar\baz)#4 (0) < >>

The protected class \foo\bar\baz can now be used in \foo , for example:

object(foo)#1 (3) < ["bar"]=>object(foo\bar)#2 (1) < ["baz"]=>object(foo\bar\baz)#3 (0) < >> ["baz"]=> object(foo\bar\baz)#4 (0) < >["qux"]=> object(foo\qux)#5 (0) < >>

Backward Incompatible Changes

A single test that was defined in Zend/tests to check that an error is emitted when you declare a nested class; in reality, nothing core is broken.

Proposed PHP Version(s)

SAPIs Impacted

Impact to Existing Extensions

Existing libraries that work directly with zend_class_entry structures will need to update to include the additional member of the struct “super”; the member is used to store a pointer to the class that created it.

Such an update should not cause any real inconvenience.

Reflection requires patching to be able to report information about outer classes and access levels.

Open Issues

Access to private statics members in outer classes (access to methods requires some adjustment too).

Источник

Читайте также:  Python и web камера
Оцените статью