# Inconsistencies with constructors in SPL

- Thread: https://externals.io/message/52399
- Original archive: https://news-web.php.net/php.internals/52399
- Started by Andrew Curioso on 2011-05-16T18:14:04+00:00
- Messages: 20
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #52399 — Andrew Curioso — 2011-05-16T18:14:04+00:00

URL: https://externals.io/message/52399#52399

So, I ran across bug #54631

A fatal error is thrown if you try to call parent::__construct() from a
subclass
of SplObjectStorage.

I was going to close it as "expected behavior" since that is pretty normal
if the parent class doesn't implement __construct().
Also, the docs don't list it as having a __construct() method.

But then look at SplDoublyLinkedList (and a bunch of others). They are
documented
as having a __construct() method, yet it triggers a fatal error when you try
to call
"parent::__construct()" from a subclass' constructor .

So it seems to me that there are two possible solutions:

- Update the docs to remove ::__construct() for classes that don't have one.
- Make sure __construct() is implemented in all SPL classes * and update the
docs.

* Even if it is empty.

What's everyone thinking?

I'd be more than happy to add the constructors to the code where needed, I
just
want to make sure that it is the right move first.


- Andrew

---

## #52400 — Stas Malyshev — 2011-05-16T18:28:47+00:00

URL: https://externals.io/message/52399#52400 · In reply to: #52399

Hi!

> A fatal error is thrown if you try to call parent::__construct() from a
> subclass
> of SplObjectStorage.

I'm thinking maybe it'll be useful to make parent::__construct silently 
succeed if parent class exists but has no ctor.

The reason for that that for many classes you _have_ to call parent ctor 
for normal functionality, on the other hand some of them may not have it 
clearly documented if ctor method exists or not. Also, even if ctor 
method doesn't exist in fact there's always default empty one (since you 
can create object without explicitly writing a ctor).
So, if we allow parent ctor always succeed it will make the code more 
robust.
What do you think?
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #52401 — johannes@schlueters.de — 2011-05-16T18:32:00+00:00

URL: https://externals.io/message/52399#52401 · In reply to: #52399

Hi,

I|d actuallz suggest a different option:

If a parent constructor is called but doesn't exist the engine should
ignore this. The same goes for destructors.

This solution would also work for userland classes.

johannes


> So, I ran across bug #54631
> 
> A fatal error is thrown if you try to call parent::__construct() from a
> subclass
> of SplObjectStorage.
> 
> I was going to close it as "expected behavior" since that is pretty normal
> if the parent class doesn't implement __construct().
> Also, the docs don't list it as having a __construct() method.
> 
> But then look at SplDoublyLinkedList (and a bunch of others). They are
> documented
> as having a __construct() method, yet it triggers a fatal error when you try
> to call
> "parent::__construct()" from a subclass' constructor .
> 
> So it seems to me that there are two possible solutions:
> 
> - Update the docs to remove ::__construct() for classes that don't have one.
> - Make sure __construct() is implemented in all SPL classes * and update the
> docs.
> 
> * Even if it is empty.
> 
> What's everyone thinking?
> 
> I'd be more than happy to add the constructors to the code where needed, I
> just
> want to make sure that it is the right move first.
> 
> 
> - Andrew

---

## #52402 — Andrew Curioso — 2011-05-16T18:44:23+00:00

URL: https://externals.io/message/52399#52402 · In reply to: #52401

I like that idea and I like that it works for userland classes as well.

+1

Do you think it should throw a warning, notice, or -- as you both suggested
-- just silently succeed?




2011/5/16 Johannes Schlüter <johannes@schlueters.de>

> Hi,
>
> I|d actuallz suggest a different option:
>
> If a parent constructor is called but doesn't exist the engine should
> ignore this. The same goes for destructors.
>
> This solution would also work for userland classes.
>
> johannes
>
> 
> > […]
> normal
> > […]
> try
> > […]
> one.
> > […]
> the
> > […]
> I
> > […]

---

## #52403 — Anthony Ferrara — 2011-05-16T19:10:00+00:00

URL: https://externals.io/message/52399#52403 · In reply to: #52402

Personally, I really don't care for something like this.  Would it be
caught by a __call declaration if one existed (since it is a call to
an undefined method)?  Would you expect it to?

I'd rather see calls to non-existent methods generate a catachable
fatal error (rather than a hard fatal error that's currently thrown).
That way we can use an error exception to "catch" the fatal and
recover from it if necessary.

But silently ignoring a called function, something just doesn't sit
right about that...




> I like that idea and I like that it works for userland classes as well.
>
> +1
>
> Do you think it should throw a warning, notice, or -- as you both suggested
> -- just silently succeed?
>
>
>
>
> 2011/5/16 Johannes Schlüter <johannes@schlueters.de>
>
> > […]

---

## #52404 — Andrew Curioso — 2011-05-16T19:18:14+00:00

URL: https://externals.io/message/52399#52404 · In reply to: #52403

To play devil's advocate a bit:

It's a special case. If it was really an undefined method then this is
suddenly ambiguous:
$foo = new Foo();

If __construct() is undefined, what is being called in that case? By the
same logic, that should
throw an error as well.

On the other hand, if __construct is presumed to be implicitly defined then
I think it makes
logical sense for parent::__construct() to always succeed.

Side note:
If __construct is implicit then __destruct should also be.







On Mon, May 16, 2011 at 3:10 PM, Anthony Ferrara <ircmaxell@gmail.com>wrote:

> Personally, I really don't care for something like this.  Would it be
> caught by a __call declaration if one existed (since it is a call to
> an undefined method)?  Would you expect it to?
>
> I'd rather see calls to non-existent methods generate a catachable
> fatal error (rather than a hard fatal error that's currently thrown).
> That way we can use an error exception to "catch" the fatal and
> recover from it if necessary.
>
> But silently ignoring a called function, something just doesn't sit
> right about that...
>
>
>
> On Mon, May 16, 2011 at 2:44 PM, Andrew Curioso <andrewcurioso@gmail.com>
> wrote:
> > […]
> suggested
> > […]
> a
> > […]
> you
> > […]
> have
> > […]
> update
> > […]
> needed,
> > […]
>



-- 
Andrew Curioso

---

## #52405 — Stas Malyshev — 2011-05-16T19:23:22+00:00

URL: https://externals.io/message/52399#52405 · In reply to: #52403

Hi!

> Personally, I really don't care for something like this.  Would it be
> caught by a __call declaration if one existed (since it is a call to
> an undefined method)?  Would you expect it to?

No and no. __call is not called for ctors, for obvious reasons (__call 
is an object method, and before ctor is done the object is not ready). 
It was always this way.

> I'd rather see calls to non-existent methods generate a catachable
> fatal error (rather than a hard fatal error that's currently thrown).

Personally, I like this "catchable fatal error" business less and less. 
It's an awkward way of doing an exception with all exception downsides 
and none of the upsides...

> But silently ignoring a called function, something just doesn't sit
> right about that...

We're already doing it :) Try:
class Foo {}
$a = new Foo();

You just ignored a non-existing ctor.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #52406 — Anthony Ferrara — 2011-05-16T19:28:58+00:00

URL: https://externals.io/message/52399#52406 · In reply to: #52404

Well, if we follow that logic (which does make sense), then shouldn't
all magic methods be implicit?  So parent::__sleep/__call/__get/etc
would silently do the default if not defined?


> To play devil's advocate a bit:
>
> It's a special case. If it was really an undefined method then this is
> suddenly ambiguous:
> $foo = new Foo();
>
> If __construct() is undefined, what is being called in that case? By the
> same logic, that should
> throw an error as well.
>
> On the other hand, if __construct is presumed to be implicitly defined then
> I think it makes
> logical sense for parent::__construct() to always succeed.
>
> Side note:
> If __construct is implicit then __destruct should also be.
>
>
>
>
>
>
>
> On Mon, May 16, 2011 at 3:10 PM, Anthony Ferrara <ircmaxell@gmail.com>
> wrote:
> > […]
>
>
>
> --
> Andrew Curioso

---

## #52407 — Anthony Ferrara — 2011-05-16T19:37:02+00:00

URL: https://externals.io/message/52399#52407 · In reply to: #52405

> No and no. __call is not called for ctors, for obvious reasons (__call is an
> object method, and before ctor is done the object is not ready). It was
> always this way.

It is called from constructors, just not *for* constructors:

class test {
    public static function __callStatic($name, $args) {
        printf("Static: %s\n", $name);
    }
    public function __call($name, $args) {
        printf("Parent Instance: %s\n", $name);
    }
}

class test2 extends test {
    public function __construct() {
        $this->bar();
        parent::__construct();
    }
    public function __call($name, $args) {
        printf("Instance: %s\n", $name);
    }
}
$foo = new Test2();

Results in:
Instance: bar
PHP Fatal error:  Cannot call constructor in...

While I do agree that it *shouldn't* call __call/__callStatic for
constructors, it does for other methods...

> > […]
>
> Personally, I like this "catchable fatal error" business less and less. It's
> an awkward way of doing an exception with all exception downsides and none
> of the upsides...

That's fair, but if we buy that, let's have at least an option to
convert all errors to exceptions.  That way there are no "catchable
errors", just exceptions for errors over a specified level (E_WARNING
for example)...

> > […]
>
> We're already doing it :) Try:
> class Foo {}
> $a = new Foo();
>
> You just ignored a non-existing ctor.

I guess that's fair.  I just don't care for special-case logic in
general.  It generates too many edge-cases.  That's not saying this is
worth it or not, but just my preference...

Anthony

---

## #52408 — Andrew Curioso — 2011-05-16T19:43:15+00:00

URL: https://externals.io/message/52399#52408 · In reply to: #52406

That is a whole other can of worms. Whereas __construct() and __destruct()
can do nothing and are probably pretty trivial to get working, some other
methods aren't so clear cut.

Example: __sleep() would have to return an array of member variables so
that it does what is expected when called by the user. Like this...

...
public function __sleep()
{
  return array_merge( parent::__sleep(), array( "foo", "bar" ) );
}
...

My only point being. I like the idea in principal but implementing it for
all magic
methods could become a somewhat major undertaking.




On Mon, May 16, 2011 at 3:28 PM, Anthony Ferrara <ircmaxell@gmail.com>wrote:

> Well, if we follow that logic (which does make sense), then shouldn't
> all magic methods be implicit?  So parent::__sleep/__call/__get/etc
> would silently do the default if not defined?
>
> On Mon, May 16, 2011 at 3:18 PM, Andrew Curioso <andrewcurioso@gmail.com>
> wrote:
> > […]
> then
> > […]
> andrewcurioso@gmail.com>
> > […]
> well.
> > […]
> from
> > […]
> when
> > […]
>



-- 
Andrew Curioso

---

## #52409 — Stas Malyshev — 2011-05-16T19:45:17+00:00

URL: https://externals.io/message/52399#52409 · In reply to: #52406

Hi!

> Well, if we follow that logic (which does make sense), then shouldn't
> all magic methods be implicit?  So parent::__sleep/__call/__get/etc
> would silently do the default if not defined?

In most cases, you are required to call parent ctor, but there's no such 
requirement for other methods. Ctors are special in a way that in 99.9% 
of cases you do call parent ctor. I can't really think of any case where 
you don't want to do this. Ctors are special (well, along with dtors, 
but those aren't used as much).

In fact, Java, for example, always inserts parent ctor call if you don't 
have one and defines empty ctor so it always works. Of course, we don't 
have to follow them but this shows this pattern is known.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #52411 — Andrew Curioso — 2011-05-16T20:52:08+00:00

URL: https://externals.io/message/52399#52411 · In reply to: #52409

Well, that wasn't where I was expecting that thread to go, but to wrap it up
what do you think...
Is it too late to put this on the 5.4 roadmap for consideration?

I'm assuming just the implicit ctor and dtor. Not all magic methods (not
now, at least).

With your OK, Stas, I'd like to write up an RFC and put it on the Wiki.

- Andrew

---

## #52414 — Etienne Kneuss — 2011-05-16T21:25:11+00:00

URL: https://externals.io/message/52399#52414 · In reply to: #52411

Hi,


> Well, that wasn't where I was expecting that thread to go, but to wrap it up
> what do you think...
> Is it too late to put this on the 5.4 roadmap for consideration?
> 
> I'm assuming just the implicit ctor and dtor. Not all magic methods (not
> now, at least).
> 
> With your OK, Stas, I'd like to write up an RFC and put it on the Wiki.
> 
> - Andrew

The main problem with internal classes and ctors is that constructor
code can be placed at object init instead of in the actual ctor method.
It is actually safer to place it at object init, because then that code
is always executed and thus the internal object is not in a half
initialized state if the user overwrites the constructor and doesn't
call the parent.

I'd rather have ctors/dtors explicitely defined in SPL. If they are
documented to exist, they should be explicitely defined. We can define
such NOOP methods globally, so that it is easy for internal classes to add
them.

As far as implicitly ignore of the constructor, I believe we have enough
magic regarding ctors/dtors in the engine as it is.

Best,

---

## #52416 — Andrew Curioso — 2011-05-16T22:10:43+00:00

URL: https://externals.io/message/52399#52416 · In reply to: #52414

I had given up on someone actually going with one of my original ideas for
fixing the bug!
That is where I was leaning but I would take it a step further and add
constructors to all SPL classes even if the docs don't currently list one.

In regards to the implicit ctor and dtor. I don't thing it is actually any
more or less magic than what we have now.
Ask a Java programmer, they will likely say that having the implicit ctor
and dtor just makes sense and not having one is strange.

Although, in Java, all classes descend from Object so it is not quite the
same.

Side not: of course, an RFC does not mean that it will end up in a release.
It would still need to be voted on.





>
> The main problem with internal classes and ctors is that constructor
> code can be placed at object init instead of in the actual ctor method.
> It is actually safer to place it at object init, because then that code
> is always executed and thus the internal object is not in a half
> initialized state if the user overwrites the constructor and doesn't
> call the parent.
>
> I'd rather have ctors/dtors explicitely defined in SPL. If they are
> documented to exist, they should be explicitely defined. We can define
> such NOOP methods globally, so that it is easy for internal classes to add
> them.
>
> As far as implicitly ignore of the constructor, I believe we have enough
> magic regarding ctors/dtors in the engine as it is.
>
> Best,

---

## #52417 — Benjamin Dubois — 2011-05-17T00:22:30+00:00

URL: https://externals.io/message/52399#52417 · In reply to: #52414

Hi,

Why not make all objects (maybe implicitly) extend a single root object, containing just skeleton ctor/dtor and implemented in the engine ?

I don't know if it is actually  possible in PHP, but that works for several other languages (java, objC - in that case, the root object is explicit-, C# AFAR)

This would also bypass the error-level debate (no error would be thrown)



--
Regards,
Benjamin Dubois



Le 16 mai 2011 à 23:25, Etienne Kneuss a écrit :

> Hi,
> 
> 
> > […]
> 
> The main problem with internal classes and ctors is that constructor
> code can be placed at object init instead of in the actual ctor method.
> It is actually safer to place it at object init, because then that code
> is always executed and thus the internal object is not in a half
> initialized state if the user overwrites the constructor and doesn't
> call the parent.
> 
> I'd rather have ctors/dtors explicitely defined in SPL. If they are
> documented to exist, they should be explicitely defined. We can define
> such NOOP methods globally, so that it is easy for internal classes to add
> them.
> 
> As far as implicitly ignore of the constructor, I believe we have enough
> magic regarding ctors/dtors in the engine as it is.
> 
> Best,

---

## #52418 — Christian Kaps — 2011-05-17T06:19:27+00:00

URL: https://externals.io/message/52399#52418 · In reply to: #52417

Am 17.05.2011 um 02:22 schrieb Benjamin Dubois <benjamin.dubois@gmail.com>:

> Hi,
> 
> Why not make all objects (maybe implicitly) extend a single root object, containing just skeleton ctor/dtor and implemented in the engine ?
> 
> I don't know if it is actually  possible in PHP, but that works for several other languages (java, objC - in that case, the root object is explicit-, C# AFAR)
> 
> This would also bypass the error-level debate (no error would be thrown)
> 

+1

---

## #52419 — Alexey Zakhlestin — 2011-05-17T06:42:34+00:00

URL: https://externals.io/message/52399#52419 · In reply to: #52417

On Tue, May 17, 2011 at 4:22 AM, Benjamin Dubois
<benjamin.dubois@gmail.com> wrote:

> Why not make all objects (maybe implicitly) extend a single root object, containing just skeleton ctor/dtor and implemented in the engine ?
>
> I don't know if it is actually  possible in PHP, but that works for several other languages (java, objC - in that case, the root object is explicit-, C# AFAR)
>
> This would also bypass the error-level debate (no error would be thrown)

+1

-- 
Alexey Zakhlestin, http://twitter.com/jimi_dini
http://www.milkfarmsoft.com/

---

## #52420 — Peter Cowburn — 2011-05-17T08:39:50+00:00

URL: https://externals.io/message/52399#52420 · In reply to: #52414

Hi folks,


> Hi,
>
> 
> > […]
>
> The main problem with internal classes and ctors is that constructor
> code can be placed at object init instead of in the actual ctor method.
> It is actually safer to place it at object init, because then that code
> is always executed and thus the internal object is not in a half
> initialized state if the user overwrites the constructor and doesn't
> call the parent.
>
> I'd rather have ctors/dtors explicitely defined in SPL. If they are
> documented to exist, they should be explicitely defined. We can define
> such NOOP methods globally, so that it is easy for internal classes to add
> them.

This.  In the short term, regardless of what happens with the code,
the documentation should reflect what is available in the language. If
a constructor is documented but not available to call then the
documentation needs to be clear about that. Any instances of this
currently in the docs should be a bug, it's an idea to report them
onto the bugs system.

As for what changes in the code, I think it would be nice for all
(SPL) classes to have a (global, noop) constructor even if nothing of
interest happens within it so that userland developers can happily,
blindly, call the parent constructor in their classes.

As an aside, do the changes made against #54384 have any impact here?

>
> As far as implicitly ignore of the constructor, I believe we have enough
> magic regarding ctors/dtors in the engine as it is.
>
> Best,

---

## #52422 — Andrew Curioso — 2011-05-17T12:01:43+00:00

URL: https://externals.io/message/52399#52422 · In reply to: #52420

From what I can tell, whatever changes made to fix this bug, are independent
of #54384.
Bug #54384 happens when the parent ctor is not called. This bug is triggered
only when it is called.
I did a quick check of the code and that seems to be the case.

But the existence of that bug makes me think that having a __construct on
all SPL classes will be less confusing to the user.

So, on that note, back to square one. We can either:
- Implement a global SPL noop constructor to be added to all SPL classes
that don't have a constructor.
- Change the documentation to reflect that some class don't have
constructors. Leave the code unchanged but inconsistent.

I already have the code for the first option done (just not checked in) and
that seems to be where most people are leaning anyway.
I can just check that in, close bug #54631 as "Fixed in SVN and needs to be
documented" and call it a day.

Then we can save the giant roadmap altering discussions about global
implicit __construct and/or global parent object for another day.

Any objections?

- Andrew


On Tue, May 17, 2011 at 4:39 AM, Peter Cowburn <petercowburn@gmail.com>wrote:

> Hi folks,
>
> 
> > […]
> it up
> > […]
> add
> > […]
>
> This.  In the short term, regardless of what happens with the code,
> the documentation should reflect what is available in the language. If
> a constructor is documented but not available to call then the
> documentation needs to be clear about that. Any instances of this
> currently in the docs should be a bug, it's an idea to report them
> onto the bugs system.
>
> As for what changes in the code, I think it would be nice for all
> (SPL) classes to have a (global, noop) constructor even if nothing of
> interest happens within it so that userland developers can happily,
> blindly, call the parent constructor in their classes.
>
> As an aside, do the changes made against #54384 have any impact here?
>
> > […]

---

## #52440 — Martin Scotta — 2011-05-17T17:49:58+00:00

URL: https://externals.io/message/52399#52440 · In reply to: #52403

Martin Scotta


On Mon, May 16, 2011 at 4:10 PM, Anthony Ferrara <ircmaxell@gmail.com>wrote:

> Personally, I really don't care for something like this.  Would it be
> caught by a __call declaration if one existed (since it is a call to
> an undefined method)?  Would you expect it to?
>

Although current PHP implementation treat them as method, it's important to
note that constructors are not methods.

$a = new Foo ();
$a->__construct(); // encapsulation broken


> I'd rather see calls to non-existent methods generate a catachable
> fatal error (rather than a hard fatal error that's currently thrown).
> That way we can use an error exception to "catch" the fatal and
> recover from it if necessary.
>
> But silently ignoring a called function, something just doesn't sit
> right about that...
>
>
>
> On Mon, May 16, 2011 at 2:44 PM, Andrew Curioso <andrewcurioso@gmail.com>
> wrote:
> > […]
> suggested
> > […]
> a
> > […]
> you
> > […]
> have
> > […]
> update
> > […]
> needed,
> > […]
