【问题标题】:Can we create an object of a class inside another class in php?我们可以在 php 中的另一个类中创建一个类的对象吗?
【发布时间】:2012-05-17 10:30:16
【问题描述】:

我们可以在 php 中的另一个类中创建一个类的对象吗?我在 php 中做了一个小应用程序,现在我正在尝试以类-方法-对象的方式转换整个代码。我现在很困惑。

【问题讨论】:

  • 你能写一个你想做的小例子吗?
  • 也许你应该分享一些你想改变的代码示例,你应该告诉你用它尝试了什么,什么时候你开始感到困惑。 - 还请强调 PHP 手册的哪一部分没有解决您的困惑。

标签: php class object


【解决方案1】:

你可以这样做,但你是否应该这样做取决于两个类的生命周期以及它们之间的关系。基本上,您可以在CompositionAggregation 之间进行选择。

作曲

当创建的对象的生命周期等于或小于将使用它的对象时,您使用组合,例如

class A 
{
    private $belongsToAOnly;

    public function __construct()
    {
        $this->belongsToAOnly = new IBelongToA;
    }
}

在这种情况下,A“拥有”IBelongToA。当A 被销毁时,IBelongToA 也被销毁。它不能独立存在,很可能只是A 的一个实现细节。它可以是 ValueObject 之类的 Money 或其他一些数据类型。

来自 Craig Larman 的“应用 UML 和模式”:

复合体负责创建和删除它的部分——通过它自己创建/删除部分,或者通过与其他对象协作。与此约束相关的是,如果组合被破坏,它的部分必须被破坏,或者附加到另一个组合”

聚合

当创建的对象的生命周期较长时,您使用聚合:

class A 
{
    private $dbAdapter;

    public function __construct(DbAdapter $dbAdapter)
    {
        $this->dbAdapter = $dbAdapter;
    }
}

与 Composition 不同,这里没有所有权的含义。 A 使用 DbAdapter 但当 A 被销毁时 DBAdapter 继续存在。这是一种“使用”关系,而不是“拥有”关系。

创建者模式 (GRASP)

Creator Pattern in GRASP 中可以找到一个很好的启发式方法来决定一个对象何时可以在运行时创建另一个对象,它指出对象可以在何时创建其他对象

  • B 的实例包含或复合聚合了 A 的实例
  • B 的实例记录 A 的实例
  • B 的实例密切使用 A 的实例
  • B 的实例具有 A 实例的初始化信息并在创建时传递它。

或者,您可以在需要创建某些东西的实例并聚合工厂实例时创建工厂,这将为您提供更干净的separation of collaborators and creators

可测试性

在对象中创建对象产生的一个问题是它们难以测试。当您进行单元测试时,您通常不想重新创建和引导整个系统环境,而是专注于单独测试那个特定的类。为此,您可以使用Mock Objects 替换该类的依赖项。使用合成时不能这样做。

因此,根据班级的合作者所做的事情,您可能希望决定始终使用聚合,因为这样您就一直在有效地执行Dependency Injection,这将允许您轻松地更换班级的合作者,例如用 Mocks 替换它们。

【讨论】:

    【解决方案2】:

    是的,你可以,但这会增加代码耦合并使测试更加困难。
    我建议在类之外创建它并将其作为参数传递(称为依赖注入)。

    class Foo
    {
    }
    
    class Bar
    {
      public function __construct(Foo $foo)
      {
        $this->foo = $foo;
      }
    }
    
    $foo = new Foo();
    $bar = new Bar($foo);
    

    【讨论】:

    • 不好的做法,为什么?我不同意这种说法,你能说说为什么吗?
    • 一种不好的做法,因为您的课程将相互关联。这是编写好的面向对象代码的基础之一。
    • en.wikipedia.org/wiki/Facade_pattern,如果你知道自己在做什么,绑课也不错。绑定不属于同一模块/范围/域的类是一种不好的做法。封装行为很重要,松耦合是概念之间的而不是类之间的强制
    • 请不要谈论特殊情况或以这种方式设计的设计模式。规则总是有例外的。另外,我从未说过这是强制性的,它会搞砸他的代码,或者类似的事情。我只是说这是一种不好的做法。它是什么。因为,例如,你不能测试它,你不能在 Bar 内部使用另一个类(Foo f.e.的子类),你不能传递一个已经用不同参数实例化的 Foo 实例。
    • 链接是因为我这里没有空间讨论依赖注入的问题,链接只是一个备注,但如果你想开一个线程只讨论软件架构,欢迎你.没有上下文,你不能断言一件事是不好的做法,这个问题没有上下文,你只是在没有争论的情况下公开了你的观点。
    【解决方案3】:

    是的,你可以做到的..

    这是一个例子..

    a.php
    <?php
        class a{
            public function function_1(){
               echo "b";
            }
         }
    ?>
    
    
    b.php
    <?php
         include_once ("a.php");
         class b{
            public function function_b(){
                 $a = new a;
                 $a->function_1();
            }
          }
          $b= new b;
          $b->function_b();
     ?>
    

    【讨论】:

      【解决方案4】:

      是的,您可以从另一个类中的特定类创建对象。

      class SomeClass{
      
      }
      class SomeOtherClass {
           function hello(){
               $o = new SomeClass;
           }
      }
      

      【讨论】:

        【解决方案5】:

        是的,你也可以在一个类中定义一个函数。您可以在 php 中的类中完成所有操作,请将您的代码发布在您感到困惑的地方。

        示例: 类中的对象。

        class Foo
        {
           public $bar; // another object!
        
           public __construct()
           {
              $this->bar = new Bar();
            }
        }
        

        (全局)类中的函数

        <?php
            class Foo
            {
                public function __construct()
                {
                    function __construct()
                    {
                        echo "Yes, I'm a global function!";
                    }
                }
            }
        
            new Foo();
            __construct();
        
        ?>
        

        【讨论】:

        • 构造前缺少function。但我喜欢这个答案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-03
        • 2010-12-07
        相关资源
        最近更新 更多