PHP 中的嵌套类或内部类 [英] Nested or Inner Class in PHP
问题描述
我正在为我的新网站构建一个用户类,但是这次我想以稍微不同的方式构建它...
I'm building a User Class for my new website, however this time I was thinking to build it little bit differently...
C++、Java 甚至 Ruby(可能还有其他编程语言)都允许在主类中使用嵌套/内部类,这使我们能够使代码更加面向对象和组织.
C++, Java and even Ruby (and probably other programming languages) are allowing the use of nested/inner classes inside the main class, which allows us to make the code more object-oriented and organized.
在 PHP 中,我想做这样的事情:
In PHP, I would like to do something like so:
<?php
public class User {
public $userid;
public $username;
private $password;
public class UserProfile {
// some code here
}
private class UserHistory {
// some code here
}
}
?>
这在 PHP 中可行吗?我怎样才能实现它?
Is that possible in PHP? How can I achieve it?
更新
如果不可能,未来的 PHP 版本会支持嵌套类吗?
If it's impossible, will future PHP versions might support nested classes?
推荐答案
Intro:
嵌套类与其他类的关系与外部类略有不同.以Java为例:
Intro:
Nested classes relate to other classes a little differently than outer classes. Taking Java as an example:
非静态嵌套类可以访问封闭类的其他成员,即使它们被声明为私有.此外,非静态嵌套类需要实例化父类的实例.
Non-static nested classes have access to other members of the enclosing class, even if they are declared private. Also, non-static nested classes require an instance of the parent class to be instantiated.
OuterClass outerObj = new OuterClass(arguments);
outerObj.InnerClass innerObj = outerObj.new InnerClass(arguments);
使用它们有几个令人信服的理由:
There are several compelling reasons for using them:
- 这是一种对仅在一个地方使用的类进行逻辑分组的方法.
如果一个类只对另一个类有用,那么合乎逻辑将其关联并嵌入到该类中,并将两者保持在一起.
If a class is useful to only one other class, then it is logical to relate and embed it in that class and keep the two together.
- 它增加了封装性.
- 嵌套类可以使代码更具可读性和可维护性.
考虑两个顶级类 A 和 B,其中 B 需要访问否则将被声明为私有的 A 成员.通过隐藏类B 在类 A 中,A 的成员可以声明为私有,B 可以访问他们.此外,B 本身可以对外界隐藏.
Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.
嵌套类通常与它的父类相关并一起形成一个包"
A nested class usually relates to it's parent class and together form a "package"
在 PHP 中
您可以在没有嵌套类的情况下在 PHP 中拥有类似的行为.
如果您只想实现结构/组织,如 Package.OuterClass.InnerClass,PHP 命名空间可能就足够了.您甚至可以在同一个文件中声明多个命名空间(尽管由于标准的自动加载功能,这可能是不可取的).
If all you want to achieve is structure/organization, as Package.OuterClass.InnerClass, PHP namespaces might sufice. You can even declare more than one namespace in the same file (although, due to standard autoloading features, that might not be advisable).
namespace;
class OuterClass {}
namespace OuterClass;
class InnerClass {}
如果您希望模拟其他特征,例如成员可见性,则需要更多的努力.
If you desire to emulate other characteristics, such as member visibility, it takes a little more effort.
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 PackageMyParentPublicChild();
//instantiate protected child inside parent
$this->protectedChild = new PackageMyParentProtectedChild();
}
public function test() {
echo "Call from parent -> ";
$this->publicChild->protectedMethod();
$this->protectedChild->protectedMethod();
echo "<br>Siblings<br>";
$this->publicChild->callSibling($this->protectedChild);
}
}
}
namespace PackageMyParent
{
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<br>";
}
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<br>";
}
protected function callSibling($sibling) {
echo "Call from " . get_class($this) . " -> ";
$sibling->protectedMethod();
}
}
}
测试
$parent = new PackageMyParent();
$parent->test();
$pubChild = new PackageMyParentPublicChild();//create new public child (possible)
$protChild = new PackageMyParentProtectedChild(); //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
<小时>
注意:
我真的不认为尝试在 PHP 中模拟 innerClasses 是一个好主意.我认为代码不太干净和可读.此外,可能还有其他方法可以使用完善的模式(例如观察者、装饰者或组合模式)来实现类似的结果.有时,即使是简单的继承也足够了.
NOTE:
I really don't think trying to emulate innerClasses in PHP is such a good idea. I think the code is less clean and readable. Also, there are probably other ways to achieve similar results using a well established pattern such as the Observer, Decorator ou COmposition Pattern. Sometimes, even simple inheritance is sufficient.
这篇关于PHP 中的嵌套类或内部类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!