PHP中的嵌套或内部类 [英] Nested or Inner Class in PHP

查看:116
本文介绍了PHP中的嵌套或内部类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的新网站建立用户类,但这一次我正在考虑建立一些不同...



我知道 C ++ Java 甚至 Ruby (可能还有其他编程语言)允许在主类中嵌套/使代码更加面向对象和组织。



在PHP中,我想这样做:

 <?php 
public class User {
public $ userid;
public $ username;
private $ password;

public class UserProfile {
//这里的一些代码
}

私人类UserHistory {
//这里的一些代码
}
}
?>

PHP中有可能吗?如何实现?






UPDATE $ b

如果不可能,未来的PHP版本是否支持嵌套类?

解决方案

简介:



嵌套类与其他类相关,有别于外层类。以Java为例:



非静态嵌套类可以访问包含类的其他成员,即使它们被声明为私有。此外,非静态嵌套类需要实例化父类的实例。

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

有几个令人信服的理由使用它们:




  • 这是一种逻辑分组只在一个地方使用的类的方法。




如果一个类只对另一个类有用,那么逻辑到





  • 它增加了封装。




考虑两个顶级类A和B,其中B需要访问
的A否则将被声明为私有。通过在类A中隐藏类
B,A的成员可以被声明为私有的,B可以访问
。此外,B本身可以从外部世界隐藏。





  • 嵌套类可以导致更加可读和可维护代码。




嵌套类通常与其父类关联,




在PHP



您可以类似在没有嵌套类的PHP中的行为。



如果你想实现的是结构/组织,如Package.OuterClass.InnerClass,PHP命名空间可能会sufice。您甚至可以在同一个文件中声明多个命名空间(尽管由于标准的自动加载功能,这可能不太明智)。

  namespace; 
class OuterClass {}

命名空间OuterClass;
class InnerClass {}

如果你想模仿其他特性,需要更多的努力。



定义包类



  namespace {

class Package {

/ * protect构造函数,因此无法从外部实例化对象
*由于所有类都继承自Package类,他们可以实例化另一个
*模拟保护InnerClasses
* /
protected function __construct(){}

/ *每当一个不可访问的方法被调用
*(通过可见性禁忌或不存在)
*这里我们模拟package类的共享保护方法
*此方法被Package $的所有子类继承b $ b * /
public function __call($ method,$ args){

//类名
$ class = get_class($ this);

/ *我们检查一个方法是否存在,如果不是我们抛出异常
*类似于默认错误
* /
if(method_exists($ this, $ method)){

/ *该方法存在,所以现在我们想知道
*调用者是否是我们的Package类的子类。如果不是我们抛出一个异常
*注意:这是一种肮脏的方式找出谁是
*通过使用debug_backtrace和反射调用该方法
* /
$ 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());
}
}
}
}






使用案例



 命名空间包{
class MyParent extends \Package {
public $ publicChild;
protected $ protectedChild;

public function __construct(){
//实例化父对象中的公共子对象
$ this-> publicChild = new \Package\MyParent\PublicChild();
//在父对象中实例化受保护的子
$ this-> protectedChild = new \Package\MyParent\ProtectedChild();
}

public function test(){
echoCall from parent - >;
$ this-> publicChild-> protectedMethod();
$ this-> protectedChild-> protectedMethod();

echo< br> Siblings< br>;
$ this-> publicChild-> callSibling($ this-> protectedChild);
}
}
}

命名空间Package\MyParent
{
类PublicChild扩展\Package {
//使构造函数公开,因此可以从外部调用
public function __construct(){}
protected function protectedMethod(){
echoI'm.get_class($ this)。protected method ; br>;
}

protected function callSibling($ sibling){
echoCall from。 get_class($ this)。 - >;
$ sibling-> protectedMethod();
}
}
class ProtectedChild extends \Package {
protected function protectedMethod(){
echoI'm.get_class($ this)。protected方法< br>;
}

protected function callSibling($ sibling){
echoCall from。 get_class($ this)。 - >;
$ sibling-> protectedMethod();
}
}
}



测试



  $ parent = new Package\MyParent(); 
$ parent-> test();
$ pubChild = new Package\MyParent\PublicChild(); //创建新的公共子对象(可能)
$ protChild = new Package\ MyParent\ProtectedChild(); // create new protected child(ERROR)

输出:

 来自父级 - >我是包保护的方法
我是包保护的方法

兄弟姐妹
从包调用 - >我是包保护方法
致命错误:调用受保护的Package :: __ construct()从无效的上下文


$ b b




注意:



我真的不认为试图在PHP中模仿innerClasses是一个好主意。我认为代码不那么干净和可读性。此外,可能有其他方法使用一个良好建立的模式,如观察者,装饰者ou组合模式实现类似的结果。有时,即使简单的继承也是足够的。


I'm building a User Class for my new website, however this time I was thinking to build it little bit differently...

I know that C++, Java and even Ruby (and probably other programming languages) allows nested/inner classes inside the main class which allows to make the code more Object-Oriented and organized.

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
        }
    }
?>

Is that possible in PHP? How can I achieve it?


UPDATE

If it's impossible, will future PHP versions might support nested classes?

解决方案

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:

  • It is a way of logically grouping classes that are only used in one place.

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.

  • It increases encapsulation.

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.

  • Nested classes can lead to more readable and maintainable code.

A nested class usually relates to it's parent class and together form a "package"

In PHP

You can have similar behavior in PHP without nested classes.

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.

Defining the "package" class

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()");
            }
        }
    }
}


Use case

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 "<br>Siblings<br>";
            $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<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();
        }
    }
}

Testing

$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)

Output:

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


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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆