我们可以在同一个类中声明__constructor和类名构造函数吗?

时间:2015-04-22 10:09:32

标签: php oop constructor

我们可以在同一个类中声明__constructor和类名构造函数吗?

如果是,则在创建对象时都会调用它们。这也将是序列。

如果只有一个会被调用,那么哪一个?为什么?

2 个答案:

答案 0 :(得分:3)

在此答案的下方,您会发现您的个人问题以便捷的列表格式得到了解答。但首先,请允许我向您提供一些一般信息,文档引用,链接和代码片段,以帮助您更好地理解这一切。

您可以定义两种类型的构造函数,但PHP永远不会将这两种方法同时视为构造函数,如is explained here

  

为了向后兼容,如果PHP 5找不到给定类的__construct()函数,并且该类没有从父类继承,它将搜索旧式构造函数,其名称为类。实际上,这意味着唯一具有兼容性问题的情况是该类是否有一个名为__construct()的方法,该方法用于不同的语义。

因此,如果找不到__construct方法,则同名构造函数是后备。它的主要目的是保持与无望的过时PHP版本的向后兼容性,因此它是will be removed in the next major release of PHP(PHP7将在今年晚些时候推出)的东西。 PHP7将轻轻地弃用此"功能" ,并且它将从PHP8中完全删除

  

从PHP 5.3.3开始,与命名空间类名的最后一个元素同名的方法将不再被视为构造函数。此更改不会影响非命名空间的类。

对于PHP 5.3.3及更高版本,如果您至少使用名称空间,那么相同名称的构造函数将无法完成

简而言之:

class Foo
{
    public function Foo()
    {
        //this is the constructor
    }
}

但:

class Foo
{
    public function __construct()
    {
        //this is the constructor
    }
    public function Foo()
    {
        //this is just a method
    }
}

同样值得注意的是,在同一个类中定义两个可能的构造函数会发出E_STRICT通知。但是有了例子......

或:

class Bar
{
    public function __construct()
    {
        //this is the constructor
    }
}


class Foo extends Bar
{
    public function Foo()
    {
        //this is a regular function
        //Bar::__construct is the constructor
    }
}

namespace Foo\Bar;
class Foo
{
    public function Foo()
    {
       //this is just a method
       //Foo\Bar\Foo is a class without a constructor
    }
}

基本上是这样的:

  • 您可以定义同名构造函数吗?是的,如果在类或其任何祖先上没有定义__construct方法。如果存在__construct方法,则同名构造函数将成为常规方法,PHP将发出E_STRICT通知
  • 这两个方法都会被称为构造函数吗?不,如果存在__construct方法,那就是构造函数。如果没有,将调用具有类名的方法。为什么?因为PHP5支持__construct方法,所以PHP4构造函数是向后兼容的回退机制。回退永远不会优先于默认值,这就是为什么只调用__construct方法。简单。
  • 定义两种类型的构造函数会发出E_STRICT通知(在PHP5中,如果PHP7看到PHP4样式的构造函数,PHP7将发出E_DEPRECATED通知。)
  • 如果您的类是命名空间,则它取决于PHP版本5.3.3,并且只能使用__construct方法。鉴于我们目前的版本为5.6,而PHP7将于今年发布,我不会编写需要弃用PHP版本的代码
  • PHP7即将到期,it breaks backwards compatibility

总而言之,很久以前,同名构造函数已被__construct取代,所以我会使用它。更重要的是:使用基于名称的构造函数机制非常容易出错,因为在继承链的某个地方找到__construct方法时,它们会变成常规方法。使用两个发出通知,这意味着significant performance hit 如果 真的 想要,那么可能可能会想到可能会梦想写下以下内容:

class Foo
{
    private $constructed = false;
    public function __construct()
    {
        if ($this->constructed === false)
        {
            $this->Foo();
        }
    }
    public function Foo()
    {
        $this->constructed = true;
        //do constructor stuff...
    }
}

在混音中添加继承,你最终会得到这个:

class BaseClass//the parent
{
    protected $constructed = false;
    final public function __construct()
    {
        if ($this->constructed === false)
        {
            $class = explode('\\', get_class($this));
            $method = end($class);
            if (method_exists($this, $method))
            {
               //use func_get_args_array() + call_user_func_array
               //if your constructor takes arguments:
               call_user_func_array(
                   array($this, $method),
                   func_get_args_array()
               );
               $this->constructed = true;
               //simple version: $this->{$method}();
            }
        }
    }
}

但是,让我们诚实一下,这真的是一件愚蠢的事情,不会吗?那个,并且通过使用这种方法没有解决通知,所以你仍然必须考虑那些通知。如果您的子类构造函数需要参数,那么,至少在第二种情况下,您的构造函数会破坏liskov原则(继承的合同违规)。

答案 1 :(得分:0)

是的,你可以,但它对我有意义,你为什么要这样做, 如果您喜欢某些功能,请使用承包商覆盖。 在PHP 5.3.3中,类名方法被视为正常函数, 例如。

<?php
namespace Foo;
class Bar {
    public function Bar() {
        // treated as constructor in PHP 5.3.0-5.3.2
        // treated as regular method as of PHP 5.3.3
    }
}
?>

它在版本5.3.3或更高版本中的意思是你必须声明像__construct这样的构造函数 如果同时使用它们,则类名构造函数将不起作用。