在PHP中,我们能够在另一个类内部创建一个类的对象吗?

7

在php中,我们可以在另一个类中创建一个类的对象吗?我已经用php编写了一个小应用程序,现在正在尝试将整个代码转换为类-方法-对象。我现在感到困惑。


2
你能写一个小例子来说明你想做什么吗? - Yago Riveiro
2
也许你应该分享一些你想要修改的代码,并告诉我们你尝试了什么以及在哪个阶段开始感到困惑。此外,请明确指出 PHP 手册中哪一部分没有解决你的困惑。 - hakre
5个回答

17

你可以这样做,但是否应该这样做取决于两个类的生命周期及它们之间的关系。基本上,你可以选择使用组合聚合

组合

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

class A 
{
    private $belongsToAOnly;

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

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

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

复合体负责创建和删除其部分 - 要么通过自己创建/删除零件,要么通过与其他对象合作。与此约束相关的是,如果复合体被销毁,则其零件必须被销毁或附加到另一个复合体上"

聚合

当所创建对象的生存期较长时,使用聚合:

class A 
{
    private $dbAdapter;

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

与组合不同,这里没有所有权的暗示。 A 使用 DbAdapter 但当 A 被销毁时,DBAdapter 还存在。这是一种“使用”关系而不是“拥有”关系。

创建者模式 (GRASP)

判断一个对象是否可以在运行时创建另一个对象的好方法可以在GRASP中的创建者模式中找到,它说明当对象含有或组成了A类实例、记录A类实例、紧密地使用A类实例或能够提供A类实例初始化信息并传递给它们进行创建时,对象可以在运行时创建其他对象。

或者,每当需要创建某个实例并聚合工厂实例时,就可以创建工厂,这将使您获得更清晰的协作者和创建者分离

可测试性

创建对象内部的问题是很难测试它们。当进行单元测试时,通常不希望重新创建和引导整个系统环境,而是集中于仅测试该特定类的隔离性。为了实现这一点,您可以使用Mock对象替换该类的依赖项。当您使用组合时,无法做到这一点。

因此,根据类的协作者的操作,您可能希望始终使用聚合,因为这样您就可以完全进行依赖注入,这将允许您轻松地替换类的协作者,例如用模拟代替它们。


7

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

class Foo
{
}

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

$foo = new Foo();
$bar = new Bar($foo);

1
外观模式:http://en.wikipedia.org/wiki/Facade_pattern。如果您知道自己在做什么,那么绑定类并不是坏事。但是,将不属于同一模块/范围/域的类绑定在一起是一种不好的实践。封装行为很重要,概念之间的松耦合是必要的,但类之间的松耦合并非强制性的。 - Yago Riveiro
2
链接是因为我在这里没有足够的空间来讨论依赖注入,链接只是一条备注,但如果你想开一个线程来讨论软件架构,欢迎你。你不能在没有上下文的情况下断言某个事物是不好的实践,问题没有上下文,你只是暴露了你的观点而没有论据。 - Yago Riveiro
完全同意Yago的观点,Samy,在没有上下文的情况下不能说这是一种不好的做法。在登录上下文中,创建一个类的对象(例如加密密码)在Login类中肯定是有意义的,因为你可能不需要在这个登录类之外加密密码。 - SuN
我的帖子已经两年了。在此期间,我做了很多Java/Scala开发,我不再认为这是一种不好的做法。尽管如此,在这样做之前,我仍然鼓励三思而后行,因为它会增加代码耦合并使测试更加困难。 - Samy Dindane
我更新了我的帖子。抱歉我太固执了,我太喜欢“良好的实践”和Symfony时髦的东西了。 :D - @YagoRiveiro - Samy Dindane
显示剩余5条评论

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();
 ?>

2

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

class SomeClass{

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

1

是的,您也可以在类中定义函数。在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();

?>

在结构体之前缺少一个“函数”。但我喜欢这个答案。 - PeMa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接