Calling PHP Parent Constructors With Old/New Synta

2019-02-12 06:04发布

问题:

Given the class Foo with an old-style constructor

class Foo
{
    public function Foo()
    {
        //does constructing stuff
    }
}

Is there any functional difference between calling the parent constructor with a new style constructor or the old style constructor?

class Bar extends Foo
{
    public function Bar()
    {
        //does it matter?
        //parent::__construct();
        //parent::Foo();
    }
}

Put another way, is there anything special about the static call

parent::__construct()

when it's made from a constructor, or is it just a standard static call?

Before the Best Practices Flying Monkeys descend, I'm dealing with some legacy code and trying to understand the consequences of everything that's going on.

回答1:

I would say both syntax do exactly the same thing...
Edit : after writting the rest of the answer, actually, this is not entirely true ^^ It depends on what you declare ; see the two examples :


If you define Foo as constructor, and call it with __construct, it seems it's working ; the following code :

class Foo {
    public function Foo() {
        var_dump('blah');
    }
}

class Bar extends Foo {
    public function Bar() {
        parent::__construct();
    }
}

$a = new Bar();

Outputs

string 'blah' (length=4)

So, all OK for now ;-)


On the other way, if you define __construct, and call Foo, like this :

class Foo {
    public function __construct() {
        var_dump('blah');
    }
}

class Bar extends Foo {
    public function Bar() {
        parent::Foo();
    }
}

$a = new Bar();

It'll get you a Fatal Error :

Fatal error: Call to undefined method Foo::foo()

So, if your class is declared with old-syntax, you can call it both ways ; and if it's defined with new (PHP5) syntax, you must use that new syntax -- which makes sense, afterall :-)


BTW, if you want some kind of "real proof", you can try using the Vulcan Logic Disassembler, that will give you the opcodes corresponding to a PHP script.


EDIT after the comment

I've uploaded the outputs of using VLD with both syntaxes : - vld-construct-new.txt : when declaring __construct, and calling __construct. - vld-construct-old.txt : when declaring Foo, and calling __construct.

Doing a diff between the two files, this is what I get :

$ diff vld-construct-old.txt vld-construct-new.txt
25c25
< Function foo:
---
> Function __construct:
29c29
< function name:  Foo
---
> function name:  __construct
44c44
< End of function foo.
---
> End of function __construct.
71c71
< Function foo:
---
> Function __construct:
75c75
< function name:  Foo
---
> function name:  __construct
90c90
< End of function foo.
---
> End of function __construct.

(Unified diff is much longer, so I'll stick to using the default format of "diff" here)

So, the only differences in the disassembled opcodes are the names of the functions ; both in the Foo class and in the Bar class (that inherits the __construct / Foo method of class Foo).

What I would really say is :

  • If you are writting PHP 5 code (and, in 2009, I sincerely hope you do ^^ ), then, just use the __construct syntax
  • You you have to maintain some old PHP 4 code you can't migrate to PHP 5 (you should), then, use the Foo syntax...


As the sidenote, the documentation says (quoting) :

For backwards compatibility, if PHP 5 cannot find a __construct() function for a given 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.

So, I really think there is not that much of a difference :-)


Did you encounter some kind of strange problem, that you think is caused by something like a difference between the two syntaxes ?



回答2:

As of PHP 5.3.3 the old style ctor will not work when you are using namespaces.

See http://www.php.net/archive/2010.php#id2010-07-22-2