我们可以在同一个类中声明__constructor和类名构造函数吗? [英] Can we declare __constructor and class name constructor in same class?

查看:105
本文介绍了我们可以在同一个类中声明__constructor和类名构造函数吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can we declare __constructor and class name constructor in same class?

如果是,则在创建对象时都会调用这两个方法。

If yes, does both get called when object gets created. Also what will be the sequence.

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

If only one will get called then which one? and Why?

推荐答案

在此答案中,您会发现自己方便的问题列表格式。但是首先,请允许我为您提供一些一般信息,文档引号,链接和代码段,它们将帮助您更好地理解所有这些内容。

Further down this answer you'll find your individual questions answered in a handy list format. But first, allow me to give you some general information, documentation quotes, links and code snippets that'll help you understand all this a bit better.

您可以定义两个类型的构造函数,但是PHP永远不会将这两种方法同时视为构造函数,例如在这里解释

You can define both types of constructors, but PHP will never treat both methods as constructors at the same time, as is explained here:


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

For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, and the class did not inherit one from a parent class, it will search for the old-style constructor function, by the name of the class. Effectively, it means that the only case that would have compatibility issues is if the class had a method named __construct() which was used for different semantics.

因此,如果没有找到 __ construct 方法,则同一个名称构造函数将作为备用。其主要目的是保持与无可救药的过时版本的PHP的向后兼容性,因此该将在PHP的下一个主要版本(今年晚些时候将推出PHP7)。 PHP7将轻柔地弃用此功能 ,并将其从PHP8中完全删除。

so the same name constructor is a fallback if no __construct method is found. Its main purpose is to maintain backwards compatibility with hopelessly outdated versions of PHP, so it's something that will be removed in the next major release of PHP (PHP7 is coming later this year). PHP7 will softly deprecate this "feature", and it'll be removed completely from PHP8


5.3.3,与命名空间类名称的最后一个元素具有相同名称的方法将不再被视为构造函数。

As of PHP 5.3.3, methods with the same name as the last element of a namespaced class name will no longer be treated as constructor. This change doesn't affect non-namespaced classes.

在PHP 5.3.3及更高版本中,如果您使用的是命名空间,则此更改不会影响非命名空间的类。至少,同名构造函数根本无法工作

In case of PHP 5.3.3 and up, if you're using namespaces at least, the same-name constructors won't work at all

因此,简而言之:

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 通知。但是下面的例子...

It's also worth noting that defining both possible constructors in the same class emits an E_STRICT notice. But on with the examples...

或:

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会发出 E_DEPRECATED 注意,如果看到的是PHP4样式的构造函数。)

  • 如果您的类已命名,则取决于PHP版本5.3.3,并且最多仅使用 __ construct 方法。鉴于我们当前使用的是5.6版,而PHP7将于今年发布,因此我不会编写要求PHP版本已弃用的代码

  • PHP7即将发布,而它破坏了向后兼容性

  • Can you define a same-name constructor? Yes, if there is no __construct method defined on the class or any of its ancestors. If a __construct method exists, the same-name constructor becomes a regular method, and PHP will emit a E_STRICT notice
  • Will both methods be called as constructor? No, if a __construct method exists, that's the constructor. If not, the method with the class name will be called. Why? Because PHP5 favours the __construct methods, the PHP4 constructors is a backwards-compatibility fallback mechanism. Fallbacks will never take precedence over the default, that's why only the __construct method will be invoked. Simple.
  • Defining both types of constructors emits an E_STRICT notice (in PHP5, PHP7 will emit an E_DEPRECATED notice if it sees a PHP4-style constructor).
  • If your class is namespaced, it depends on the PHP version 5.3.3 and up will only use __construct methods. Given that we're currently on version 5.6, and PHP7 is due this year, I wouldn't write code that requires a deprecated PHP version
  • PHP7 is due soon, and it breaks backwards compatibility

总而言之,很早以前,同名构造函数已由 __ construct 取代,所以我会用它。更重要的是:考虑到在继承链中某处找到 __ construct 方法时,它们会变成常规方法,因此使用基于名称的构造器机制很容易出错。同时使用这两种方法会发出通知,这意味着对性能产生重大影响

如果您 确实想要,您可以想像一下,也许梦想着写一些类似于以下内容的东西:

All in all, the same-name constructors have been replaced by __construct quite some time ago, so I'd use that. More over: using the name-based constructor mechanism is quite error-prone considering they turn into regular methods the moment a __construct method is found somewhere in the inheritance chain. Using both emits notices, which implies a significant performance hit
If you really want to, you could perhaps conceivably think about maybe dreaming to write something along the lines of:

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

将继承添加到混合中,您将得到以下结果:

Adding inheritance to the mix, and you'll end up with this:

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原则(继承的合同违约)。

But let's be honest for a second, that would really be a silly thing to do, wouldn't it? That, and the notices aren't solved by using this approach, so you still have to account for those notices anyway. That, and your constructor, at least in the second case, breaks the liskov principle (inherited contract breach) if your child class constructor requires arguments.

这篇关于我们可以在同一个类中声明__constructor和类名构造函数吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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