# Changes to constructor signature checks

- Thread: https://externals.io/message/56373
- Original archive: https://news-web.php.net/php.internals/56373
- Started by Ralph Schindler on 2011-11-17T21:12:41+00:00
- Messages: 16
- 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

---

## #56373 — Ralph Schindler — 2011-11-17T21:12:41+00:00

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

Hey All,

Concerning RC1, __construct() and https://wiki.php.net/rfc/prototype_checks

I think we need to round out this discussion on the __construct() 
signature checking in 5.4.  The current behavior (RC1) feels very wrong 
with respect to PHP's class based, single inheritance, multiple 
interface, no method overloading, allowed method-overriding nature.

Constructors themselves, specifically in PHP, are not explicitly 
statically marked, but are "special" (even though they are part of the 
instance API, and are callable- we'll consider this an implementation 
detail).  In general, constructor signatures have never been (and 
rightfully so) governed by the LSP.  Why? For a few reasons:

   1) before calling new(), you actually don't have a subtype (yet)- the 
subtype is a *product* of new()

   2) when you call new(), you know the exact subtype you're dealing with.

   3) only subtypes who implement or override __construct() can know how 
to prepare a stateful subtype.  In other words, parents can't know how 
to create subtypes who implement __construct() and subtypes shouldn't be 
concerned with the implementation details of how a parent creates types 
when a subtype has overridden __construct();

   4) LSP deals with behaviors and expectations of types (read: 
objects), since the constructor is generally considered "static" in 
nature, a form of factory specific to the type its defined within, and 
since in PHP you can't do (SomeClass instanceof SomeType) and since 
(is_a('SomeClass', 'SomeType') doesn't make much sense in the context of 
classes), the constructor is not subject to instance "behavior" rules.

In general, developers shouldn't be putting abstract constructors inside 
an abstract class nor should they be putting constructors inside 
interfaces- this is a well accepted bad practice.  (Neither c# or java 
allow this- of course they do have the ability to overload methods in 
classes for the record.  In fact, static methods are not allowed either.)

That said, we really should consider removing this limitation from 
constructor signature checking.  Not only is it a BC break, it doesn't 
make sense in the context of PHP.

Thoughts?

Thanks,
Ralph Schindler

---

## #56376 — Anthony Ferrara — 2011-11-17T22:14:06+00:00

URL: https://externals.io/message/56373#56376 · In reply to: #56373

Honestly, I think __construct should behave like any other method when
specified abstract or via an interface.

I know you're thinking "But it's not an LSP violation in the
constructor".  But my assertion to that is that it's a violation of
the contract that the abstract method / interface defined.  If it's a
violation of contract, I would expect to get a fatal error.  After
all, that's what a contract is for if not to enforce.

Now, you could make the argument that it's impossible to enforce a
contract (via type-hinting/instanceof) since there's no object at that
point.  So the contract isn't "signed".  And that's the *only* reason
that I could understand for wanting to change it from a fatal error to
ignored.

However, if that's taken, then I would expect to be notified that
constructors are not enforced by the interface/abstract method.
Perhaps raise a notice (or E_STRICT) in the interface on compile time
that "__construct is not enforced by interfaces"...

Additionally, what about other magic methods?  Should they be handled
separately?  I could understand a contract to enforce __invoke and
__toString, but what about the rest?  Should they be specifiable in
contract form (get/set/call/etc)?

So, actually I'm not so sure on that myself.  The Only use case I can
think of I've used here:
https://github.com/ircmaxell/PHP-CryptLib/blob/master/lib/CryptLib/Core/AbstractFactory.php#L51

Basically, it's an abstract factory that checks if a class name
implements an interface before it will "register" the class.  This is
useful for implementing proxy patterns and the such.  So we don't
actually instantiate until later.  But we want to be sure that when we
do, we'll have the proper class implementing the proper interface.
Since the factory will call `new` later, it needs to know the
constructor is valid.  So declaring the constructor in the interface
actually makes sense there...

So, my opinion is that either all magic methods (with the possible
exception of __toString and __invoke) should be excluded from
interface requirements, or none should.  Either way is fine with me,
but they should be consistent.

And I do lean on the side that the contract is the contract, and if
you change (overload) a method, you're breaking the contract.  And if
you specify the constructor in the contract (you don't have to), you
should be bound to that contract...

So I think 5.4's behavior is the proper one.  I won't be upset if it
changes, but if it does I think the rest of the magic methods (two
mentioned withstanding) should change as well...

Just my $0.02...

Anthony

On Thu, Nov 17, 2011 at 4:12 PM, Ralph Schindler
<ralph@ralphschindler.com> wrote:
> Hey All,
>
> Concerning RC1, __construct() and https://wiki.php.net/rfc/prototype_checks
>
> I think we need to round out this discussion on the __construct() signature
> checking in 5.4.  The current behavior (RC1) feels very wrong with respect
> to PHP's class based, single inheritance, multiple interface, no method
> overloading, allowed method-overriding nature.
>
> Constructors themselves, specifically in PHP, are not explicitly statically
> marked, but are "special" (even though they are part of the instance API,
> and are callable- we'll consider this an implementation detail).  In
> general, constructor signatures have never been (and rightfully so) governed
> by the LSP.  Why? For a few reasons:
>
>  1) before calling new(), you actually don't have a subtype (yet)- the
> subtype is a *product* of new()
>
>  2) when you call new(), you know the exact subtype you're dealing with.
>
>  3) only subtypes who implement or override __construct() can know how to
> prepare a stateful subtype.  In other words, parents can't know how to
> create subtypes who implement __construct() and subtypes shouldn't be
> concerned with the implementation details of how a parent creates types when
> a subtype has overridden __construct();
>
>  4) LSP deals with behaviors and expectations of types (read: objects),
> since the constructor is generally considered "static" in nature, a form of
> factory specific to the type its defined within, and since in PHP you can't
> do (SomeClass instanceof SomeType) and since (is_a('SomeClass', 'SomeType')
> doesn't make much sense in the context of classes), the constructor is not
> subject to instance "behavior" rules.
>
> In general, developers shouldn't be putting abstract constructors inside an
> abstract class nor should they be putting constructors inside interfaces-
> this is a well accepted bad practice.  (Neither c# or java allow this- of
> course they do have the ability to overload methods in classes for the
> record.  In fact, static methods are not allowed either.)
>
> That said, we really should consider removing this limitation from
> constructor signature checking.  Not only is it a BC break, it doesn't make
> sense in the context of PHP.
>
> Thoughts?
>
> Thanks,
> Ralph Schindler

---

## #56378 — Ralph Schindler — 2011-11-17T23:01:32+00:00

URL: https://externals.io/message/56373#56378 · In reply to: #56376

Inline...

> Honestly, I think __construct should behave like any other method when
> specified abstract or via an interface.

Which is not fair to say because constructors are not like instance 
methods, they are in fact "special", and not just inside PHP (more on 
that below).

> I know you're thinking "But it's not an LSP violation in the
> constructor".  But my assertion to that is that it's a violation of
> the contract that the abstract method / interface defined.  If it's a
> violation of contract, I would expect to get a fatal error.  After
> all, that's what a contract is for if not to enforce.
>
> Now, you could make the argument that it's impossible to enforce a
> contract (via type-hinting/instanceof) since there's no object at that
> point.  So the contract isn't "signed".  And that's the *only* reason
> that I could understand for wanting to change it from a fatal error to
> ignored.

So, since PHP lets you do bad things in the first place (like have 
constructors and static methods in interfaces, and abstract ctors in 
abstract classes), we follow that up with another "bad" of breaking 
general LSP expectations of how things work?

Isn't this trying to make two wrongs make a right?

> Additionally, what about other magic methods?  Should they be handled
> separately?  I could understand a contract to enforce __invoke and
> __toString, but what about the rest?  Should they be specifiable in
> contract form (get/set/call/etc)?

Again, CTOR is not "special" b/c it's a PHP "magic method" its "special" 
because it is shares qualities of being a static method as well as an 
instance method.

The rest of the __magic() methods by and large are purely instance 
methods (part of the instance API).  Having them inside an interface is 
completely logical.  (BTW, these methods can be considered 
engine-level/promoted duck typing since you don't have to implement an 
interface for them to do what they do, but that's not important here)

> So, actually I'm not so sure on that myself.  The Only use case I can
> think of I've used here:
> https://github.com/ircmaxell/PHP-CryptLib/blob/master/lib/CryptLib/Core/AbstractFactory.php#L51
>
> Basically, it's an abstract factory that checks if a class name
> implements an interface before it will "register" the class.  This is
> useful for implementing proxy patterns and the such.  So we don't

Lets look at that, the proxy pattern that is.  This is no longer valid 
usage in 5.4:

<?php

abstract class Person {
     protected $name = null;
     abstract public function __construct();
     public function setName($name)
     {
         $this->name = $name;
     }
     public function getName()
     {
         return $this->name;
     }
}

class NamedAgedPerson extends Person {
     protected $age;
     public function __construct($name, $age) { // COMMENT OUT HERE
         $this->name = $name;
         $this->age  = $age;
     }
}

class ProxyNamedAgedPerson extends NamedAgedPerson {
     public $proxy = null;
     public function __construct(NamedAgedPerson $person)
     {
         $this->proxy = $person;
     }
     public function setAge($age)
     {
         $this->proxy->age = $age;
     }
}

$np = new NamedAgedPerson('foo', 33);
$ap = new ProxyNamedAgedPerson($np);
$ap->setAge(40);
var_dump($ap);




Let's ignore the fact that it was not a very good idea to have the ctor 
in the abstract person in the first place.

In the above example, it is important to remember that an instance of 
NamedAgedPerson behaves exactly any other instance of Person in any 
situation where "instanceof Person" is the type check constraint.

There are three things wrong with this scenario.

First, if I consume a system that has practiced this abstract ctor in 
abstract class thing, I cannot create valid subtypes on my own in PHP 
5.4.  The above will throw an E_FATAL.

Secondly, (AND WORSE) is that by simply removing the abstract keyword 
from the abstract classes __construct(), I get completely different 
behavior, everything works without E_FATAL.

Thirdly, (EVEN WORSE!), is that if I comment out the $name, $age part of 
the NamedAgedPerson (see: COMMENT OUT HERE above), no E_FATAL is thrown 
on *grandchildren* who violate this abstract ctor.

So, if we choose to do this wrong+wrong=~right thing, we should at least 
do it correctly/consistently all the way through the inheritance type 
hierarchy.  Don't you think?

> And I do lean on the side that the contract is the contract, and if
> you change (overload) a method, you're breaking the contract.  And if
> you specify the constructor in the contract (you don't have to), you
> should be bound to that contract...
>
> So I think 5.4's behavior is the proper one.  I won't be upset if it
> changes, but if it does I think the rest of the magic methods (two
> mentioned withstanding) should change as well...

Of course, this argument is mostly pedantic to be honest, as I'd be 
instructing people to never attempt to put abstract ctors in abstract 
classes.  I won't be doing that either, but, the argument is largely 
that the engine shouldn't be doing these kind of things to begin off with.

Also, I'd has to see this kind of decision impacting future decisions 
(like this) b/c it was "ratified" in 5.4.

-ralph

---

## #56380 — Anthony Ferrara — 2011-11-18T04:08:33+00:00

URL: https://externals.io/message/56373#56380 · In reply to: #56378

Some responses inline...

> So, since PHP lets you do bad things in the first place (like have
> constructors and static methods in interfaces, and abstract ctors in
> abstract classes), we follow that up with another "bad" of breaking general
> LSP expectations of how things work?
>
> Isn't this trying to make two wrongs make a right?

That's why I tossed out the concept of raising a notice or `E_STRICT` 
error if a constructor is used in an interface/declared abstract.

> The rest of the __magic() methods by and large are purely instance methods
> (part of the instance API).  Having them inside an interface is completely
> logical.  (BTW, these methods can be considered engine-level/promoted duck
> typing since you don't have to implement an interface for them to do what
> they do, but that's not important here)

Well, that's true.  However, with the exception of invoke and
toString, the same functionality can be provided by the class.  __call
can be avoided by hard-coding the method (well, within reason).
__get, __set and __isset can be avoided by making the members public.
__sleep can be avoided by using the Serializable interface.  That's
why I'm pushing them in to that discussion.  It's an implementation
detail that's not really associated with the contract provided.  That
was my point (which is really not 100% related to the constructor, but
is related in passing)...

> Lets look at that, the proxy pattern that is.  This is no longer valid usage
> in 5.4:

That's not a proxy.  That's a Bridge or Adapter pattern.  Proxy
usually delays instantiation until first call (See
http://sourcemaking.com/design_patterns/proxy ).  So in your example,
the proxy class would be:

class ProxyNamedAgedPerson extends NamedAgedPerson {
   public $proxy = null;
   protected $proxyClass = '';
   public function __construct($proxyClass)
   {
       $this->proxyClass = $proxyClass;
   }
   public function setAge($age)
   {
       if (empty($this->proxy)) {
           $class = $this->proxyClass;
           $this->proxy = new $class;
       }
       $this->proxy->age = $age;
   }
}

The usage you gave would make no sense for this discussion (the
difference in constructor implementations).  However, in the proxy
example above, it makes a significant difference.  If you didn't put
it in the abstract class/interface, you could get a fatal on
instantiation.  Not saying it's hugely significant, but it's a valid
use-case.

> First, if I consume a system that has practiced this abstract ctor in
> abstract class thing, I cannot create valid subtypes on my own in PHP 5.4.
>  The above will throw an E_FATAL.

As it should, since you have a contract expecting what the subtype
doesn't implement.

> Secondly, (AND WORSE) is that by simply removing the abstract keyword from
> the abstract classes __construct(), I get completely different behavior,
> everything works without E_FATAL.

You should get different behavior.  Without Abstract, you no longer
have a contract, so there's nothing to be enforced.  Saying that's a
problem is like saying "But my code works if I remove the private
keyword from the method declaration".  It changes the meaning of the
construct significantly...  (whether abstract/inferface constructors
should be allowed is another story, but if it is, you should get the
fatal)...

> Thirdly, (EVEN WORSE!), is that if I comment out the $name, $age part of the
> NamedAgedPerson (see: COMMENT OUT HERE above), no E_FATAL is thrown on
> *grandchildren* who violate this abstract ctor.

Now that's a huge problem.  All descendants should be forced to the
same contract...  I'd classify that as a bug...

> So, if we choose to do this wrong+wrong=~right thing, we should at least do
> it correctly/consistently all the way through the inheritance type
> hierarchy.  Don't you think?

Agree

> Of course, this argument is mostly pedantic to be honest, as I'd be
> instructing people to never attempt to put abstract ctors in abstract
> classes.  I won't be doing that either, but, the argument is largely that
> the engine shouldn't be doing these kind of things to begin off with.

I don't know.  In PHP, a method is a method.  Sure, some are called
specially by the engine, but why should the constructor be any
difference (conceptually).  Sure, you usually type-hint against
interfaces after construction, but you clearly don't have to.  You
could argue if it belongs or not, and I think that's worth talking
about.  But if you want consistency, it should either apply to all
engine-called magic methods or none of them.  The two cases above
(__toString and __invoke) could be solved with a pair of interfaces
(stringable and invokable possibly) to use instead of the methods.
Then simply remove all magic methods from interfaces...  Honestly, I
don't feel strongly either way (keep all or remove all), but I think
it should be one or the other, not both...

> Also, I'd has to see this kind of decision impacting future decisions (like
> this) b/c it was "ratified" in 5.4.

Again, no argument at all.

Anthony

---

## #56383 — Ralph Schindler — 2011-11-18T05:18:37+00:00

URL: https://externals.io/message/56373#56383 · In reply to: #56380

One point that was missed, that I'd like to reiterate is that:

     Again, CTOR is not "special" b/c it's a PHP "magic
     method" its "special" because it is shares qualities
     of being a static method as well as an instance method.

That said, the constructor is not just another instance method.  Put 
another way, constructors are static methods that have instance level 
visibility access to the newly created subtype via $this.

How are they static? They are not called by $obj->__construct() as 
normal instance methods are, they are called by $obj = new 
ConcreteType() (and the engine looks for a __construct() implementation 
upwards from concrete to abstract, if it exists).

> > […]
>
> That's why I tossed out the concept of raising a notice or `E_STRICT` 
> error if a constructor is used in an interface/declared abstract.

That too would be a massive BC break.

> > […]
>
> That's not a proxy.  That's a Bridge or Adapter pattern.  Proxy
> usually delays instantiation until first call (See
> http://sourcemaking.com/design_patterns/proxy ).  So in your example,
> the proxy class would be:
>
> class ProxyNamedAgedPerson extends NamedAgedPerson {
>     public $proxy = null;
...
> The usage you gave would make no sense for this discussion (the
> difference in constructor implementations).  However, in the proxy
> example above, it makes a significant difference.  If you didn't put
> it in the abstract class/interface, you could get a fatal on
> instantiation.  Not saying it's hugely significant, but it's a valid
> use-case.


For the intents and purposes of this argument, we are using a proxy here 
- and, I'd argue that this particular pattern is central to the problem 
at hand.  (Doctrine2 also uses this pattern, to open up access to a 
entity's members as well as to provide lazy loading.)

The only real requirement is that a proxy object implements all of the 
same interfaces/parent-types as the subject object (compile time 
checking).  This ensures that for any "instanceof Subject" that you 
find, objects of type SubjectProxy and type Subject pass this is_a test, 
and can exhibit the expected behavior.

A way of obtaining this cleanly is through composition.  While you could 
have a method outside of the constructor handle the subject reference, 
the cleanest approach is:

class SubjectProxy extends Subject {
     protected $subject = null;
     public function __construct(Subject $subject) {
         $this->subject = $subject;
     }
}

I shouldn't have to care if Subject has a __construct somewhere else 
because only SubjectProxy knows how to instantiate subtypes of 
SubjectProxy in a stateful and correct way.

> > […]
>
> As it should, since you have a contract expecting what the subtype
> doesn't implement.

So, what you're promoting is that a parent type can enforce the way 
subtypes are created.

This is contrary to all understanding of class based implementations (to 
my knowledge): java or c# as far as I've checked.

Put yet another way:

*Concrete types define ctors in accordance with their own needs, not the 
needs of their parents or grandparents.*

> > […]
>
> I don't know.  In PHP, a method is a method.  Sure, some are called
> specially by the engine, but why should the constructor be any
> difference (conceptually).  Sure, you usually type-hint against

See the above comments as per why the ctors are considered special.

> interfaces after construction, but you clearly don't have to.  You
> could argue if it belongs or not, and I think that's worth talking
> about.  But if you want consistency, it should either apply to all

We couldn't consider this until php 6 though as it represents a massive 
BC break.

> engine-called magic methods or none of them.  The two cases above
> (__toString and __invoke) could be solved with a pair of interfaces
> (stringable and invokable possibly) to use instead of the methods.
> Then simply remove all magic methods from interfaces...  Honestly, I
> don't feel strongly either way (keep all or remove all), but I think
> it should be one or the other, not both...

If the honest-to-goodness goal is to be able to create dynamic types and 
be able to bypass their constructor, use the facilities that are (now) 
there for that:

http://us2.php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php

or, we can drop that functionality down into core by reusing an existing 
keyword:

$x = new Foo(empty); // bypass any __construct

Either way, my argument stands that we shouldn't be bucking the trend 
when we've been so good at adhereing to a sane is_a model with respect 
to our class/object model.

-ralph

---

## #56388 — Pierre Joye — 2011-11-18T09:29:18+00:00

URL: https://externals.io/message/56373#56388 · In reply to: #56373

hi,

On Thu, Nov 17, 2011 at 10:12 PM, Ralph Schindler
<ralph@ralphschindler.com> wrote:
> Hey All,
>
> Concerning RC1, __construct() and https://wiki.php.net/rfc/prototype_checks
>
> I think we need to round out this discussion on the __construct() signature
> checking in 5.4.  The current behavior (RC1) feels very wrong with respect
> to PHP's class based, single inheritance, multiple interface, no method
> overloading, allowed method-overriding nature.
>
> Constructors themselves, specifically in PHP, are not explicitly statically
> marked, but are "special" (even though they are part of the instance API,
> and are callable- we'll consider this an implementation detail).  In
> general, constructor signatures have never been (and rightfully so) governed
> by the LSP.  Why? For a few reasons:
>
>  1) before calling new(), you actually don't have a subtype (yet)- the
> subtype is a *product* of new()
>
>  2) when you call new(), you know the exact subtype you're dealing with.
>
>  3) only subtypes who implement or override __construct() can know how to
> prepare a stateful subtype.  In other words, parents can't know how to
> create subtypes who implement __construct() and subtypes shouldn't be
> concerned with the implementation details of how a parent creates types when
> a subtype has overridden __construct();
>
>  4) LSP deals with behaviors and expectations of types (read: objects),
> since the constructor is generally considered "static" in nature, a form of
> factory specific to the type its defined within, and since in PHP you can't
> do (SomeClass instanceof SomeType) and since (is_a('SomeClass', 'SomeType')
> doesn't make much sense in the context of classes), the constructor is not
> subject to instance "behavior" rules.
>
> In general, developers shouldn't be putting abstract constructors inside an
> abstract class nor should they be putting constructors inside interfaces-
> this is a well accepted bad practice.  (Neither c# or java allow this- of
> course they do have the ability to overload methods in classes for the
> record.  In fact, static methods are not allowed either.)
>
> That said, we really should consider removing this limitation from
> constructor signature checking.  Not only is it a BC break, it doesn't make
> sense in the context of PHP.

<?php

class A {
	function __construct($a, $b) {
	}
}

class B  extends A{
	function __construct($a) {
	}
}


works.

While the following does not:

Abstract class A {
	abstract function __construct($a, $b);
}

class B extends A{
	function __construct($a) {
	}
}

does not and it is per definition correct. Abstract defines the
signature and ensures that the signature are 100% the same.

We had a long discussion about that a couple of months ago. The main
disagreement was about the interpretation of the definition of
abstract. Abstract clearly talks about signature matching, as I (and
quite a lot of other) read it.

Cheers,
-- 
Pierre

@pierrejoye | http://blog.thepimp.net | http://www.libgd.org

---

## #56389 — Derick Rethans — 2011-11-18T09:54:59+00:00

URL: https://externals.io/message/56373#56389 · In reply to: #56373

> That said, we really should consider removing this limitation from constructor
> signature checking.  Not only is it a BC break, it doesn't make sense in the
> context of PHP.

I agree, we should not be having that check for constructors based on 
the points you raised.

cheers,
Derick

-- 
http://derickrethans.nl | http://xdebug.org
Like Xdebug? Consider a donation: http://xdebug.org/donate.php
twitter: @derickr and @xdebug

---

## #56390 — Pierre Joye — 2011-11-18T11:05:47+00:00

URL: https://externals.io/message/56373#56390 · In reply to: #56389

I strongly disagree, this encourages bad practices. We could however
reduce the error level to warning.


> 
>
> > […]
>
> I agree, we should not be having that check for constructors based on
> the points you raised.
>
> cheers,
> Derick
>
> --
> http://derickrethans.nl | http://xdebug.org
> Like Xdebug? Consider a donation: http://xdebug.org/donate.php
> twitter: @derickr and @xdebug
>
> --
> 
> 
>
>



-- 
Pierre

@pierrejoye | http://blog.thepimp.net | http://www.libgd.org

---

## #56404 — Ralph Schindler — 2011-11-18T17:40:02+00:00

URL: https://externals.io/message/56373#56404 · In reply to: #56388

Hey Pierre,

My perspective and expectations are framed by all sorts of existing 
literature as well as the discussions on this list.  It saddens me that 
you did not address any of the points I've brought up.  And, I simply 
cannot tell what basis you have for your interpretation and opinion. It 
seems more like you're basing your interpretation on preference alone.

The facts are this:

1) What we know and have been told is that PHP's signature checking is 
governed by Liskov Substitution Principle.  There are many references to 
this in the list.

I've made my argument based on the LSP.

http://marc.info/?r=1&w=2&q=b&l=php-internals&s=lsp

2) "Abstract Constructors" do not exist in any other language, for all 
intents and purposes, it's something we've invented:

http://www.google.com/search?&q=%22abstract+constructor%22

That's fine, so now the question is, how does this thing we've invented 
play in with our current implementation of a class based object model 
and how does it meet developer preexisting expectations?

3) In places that have no formal expectation and understanding in other 
programming languages, we've OFTEN favored *looseness over strictness*

Even you Pierre, once promoted "looseness"
http://news.php.net/php.internals/25089 (Pierre)

4) We should meet everyone's existing expectations, Rasmus talks about this:

http://news.php.net/php.internals/25090 (Rasmus)

and this is the general expectations:

http://www.google.com/search?q=constructor+liskov

http://stackoverflow.com/questions/5490824/should-constructors-comply-with-the-liskov-substitution-principle

> <?php
>
> class A {
> 	function __construct($a, $b) {
> 	}
> }
>
> class B  extends A{
> 	function __construct($a) {
> 	}
> }
>
>
> works.
>
> While the following does not:
>
> Abstract class A {
> 	abstract function __construct($a, $b);
> }
>
> class B extends A{
> 	function __construct($a) {
> 	}
> }


Which makes no sense b/c this does work:

abstract class A {
     abstract public function __construct($one, $two, $three);
}
class C extends A {
     public function __construct($one, $two, $three) {}
}
class D extends C {
     public function __construct($foo) {}
}

I assume this is b/c only one ->ce_parent is checked for "definition 
correctness" or whatever this new feature is we're calling ... but more 
to the point, do we really want to recurse every parent definition 
looking for an abstract __construct() and checking the signature at runtime?

> does not and it is per definition correct. Abstract defines the
> signature and ensures that the signature are 100% the same.

Where do you get your foundational basis for this?  What rules outside 
of the LSP are we looking at to make this determination?

And, can you honestly say that of the global community of developers, 
this is the expected outcome?

> We had a long discussion about that a couple of months ago. The main
> disagreement was about the interpretation of the definition of
> abstract. Abstract clearly talks about signature matching, as I (and
> quite a lot of other) read it.

According to the RFC (https://wiki.php.net/rfc/prototype_checks) a 
consensus was never reached - and more discussion was needed (which as 
of the date of the RFC and timestamps in the mailing list, has not 
happened).

-ralph

---

## #56406 — Benjamin Eberlei — 2011-11-18T18:36:58+00:00

URL: https://externals.io/message/56373#56406 · In reply to: #56404

Hey Ralph,

i think your argument on this is wrong. If we go your road:

1. Fact: PHP follows the LSP
2. Fact: The constructor is not part of the type, but a factory method.
3. Conclusion: constructors are not allowed to be part of the interface or
abstract classes.

Reversing the argument, by introducing an abstract or interfaced
constructor you actually make the constructor part of the type, hence LSP
applies. Since PHP allows this and follows LSP, this has to be enforced.

greetings,
Benjamin

On Fri, Nov 18, 2011 at 6:40 PM, Ralph Schindler
<ralph@ralphschindler.com>wrote:

> Hey Pierre,
>
> My perspective and expectations are framed by all sorts of existing
> literature as well as the discussions on this list.  It saddens me that you
> did not address any of the points I've brought up.  And, I simply cannot
> tell what basis you have for your interpretation and opinion. It seems more
> like you're basing your interpretation on preference alone.
>
> The facts are this:
>
> 1) What we know and have been told is that PHP's signature checking is
> governed by Liskov Substitution Principle.  There are many references to
> this in the list.
>
> I've made my argument based on the LSP.
>
> http://marc.info/?r=1&w=2&q=b&**l=php-internals&s=lsp<http://marc.info/?r=1&w=2&q=b&l=php-internals&s=lsp>
>
> 2) "Abstract Constructors" do not exist in any other language, for all
> intents and purposes, it's something we've invented:
>
> http://www.google.com/search?&**q=%22abstract+constructor%22<http://www.google.com/search?&q=%22abstract+constructor%22>
>
> That's fine, so now the question is, how does this thing we've invented
> play in with our current implementation of a class based object model and
> how does it meet developer preexisting expectations?
>
> 3) In places that have no formal expectation and understanding in other
> programming languages, we've OFTEN favored *looseness over strictness*
>
> Even you Pierre, once promoted "looseness"
> http://news.php.net/php.**internals/25089<http://news.php.net/php.internals/25089>(Pierre)
>
> 4) We should meet everyone's existing expectations, Rasmus talks about
> this:
>
> http://news.php.net/php.**internals/25090<http://news.php.net/php.internals/25090>(Rasmus)
>
> and this is the general expectations:
>
> http://www.google.com/search?**q=constructor+liskov<http://www.google.com/search?q=constructor+liskov>
>
> http://stackoverflow.com/**questions/5490824/should-**
> constructors-comply-with-the-**liskov-substitution-principle<http://stackoverflow.com/questions/5490824/should-constructors-comply-with-the-liskov-substitution-principle>
>
>
>  <?php
> > […]
>
>
> Which makes no sense b/c this does work:
>
> abstract class A {
>    abstract public function __construct($one, $two, $three);
> }
> class C extends A {
>    public function __construct($one, $two, $three) {}
> }
> class D extends C {
>    public function __construct($foo) {}
> }
>
> I assume this is b/c only one ->ce_parent is checked for "definition
> correctness" or whatever this new feature is we're calling ... but more to
> the point, do we really want to recurse every parent definition looking for
> an abstract __construct() and checking the signature at runtime?
>
>
>  does not and it is per definition correct. Abstract defines the
> > […]
>
> Where do you get your foundational basis for this?  What rules outside of
> the LSP are we looking at to make this determination?
>
> And, can you honestly say that of the global community of developers, this
> is the expected outcome?
>
>
>  We had a long discussion about that a couple of months ago. The main
> > […]
>
> According to the RFC (https://wiki.php.net/rfc/**prototype_checks<https://wiki.php.net/rfc/prototype_checks>)
> a consensus was never reached - and more discussion was needed (which as of
> the date of the RFC and timestamps in the mailing list, has not happened).
>
> -ralph

---

## #56407 — Anthony Ferrara — 2011-11-18T18:40:25+00:00

URL: https://externals.io/message/56373#56407 · In reply to: #56404

Comments Inline

> 1) What we know and have been told is that PHP's signature
> checking is governed by Liskov Substitution Principle.  There are
> many references to this in the list.

Except that signature checking is not needed for LSP to function.  You
can write all of your code using duck typing without interfaces and
abide by LSP 100%.  In fact, you can do things like override a
function with a signature of foo($bar, $baz) with one of foo(), and
STILL have it be LSP compliant due to the dynamic ways PHP handles
arguments.

So LSP may be a motivator, but ti's not the reason.  What could be a
reason is to enable Design-By-Contract style development where the
interface is the defined contract.  Now since PHP doesn't support
dynamic introspection of the method at run-time, the signature is the
only way of determining if the method abides by the contract.

> 2) "Abstract Constructors" do not exist in any other language, for all
> intents and purposes, it's something we've invented:

True, however in most other language constructors are not actual
methods, but a pseudo method on the object that can't be called
explicitly aside form `new` (obviously not true for all, but most of
the big ones).

Additionally, PHP is quite different from a fair bit of other
languages in that you can do things like `new $class()`.  Java and C#
don't allow this.  So to them, it's not an LSP violation or even
necessary to have it abstract since you **know** the subtype your
instantiating.  However, in PHP that's not true.  You can do
variable-class-names.  So that eliminates the assertion that you
**know** the subtype your instantiating.  You don't, and you can't.
But you can check the interface on the class name in the variable
(which is what I did in that library I posted before).    So by
specifying the constructor as abstract/interface is one way of adding
safety when you accept a class name and do dynamic instantiation...

> http://www.google.com/search?&q=%22abstract+constructor%22
>
> That's fine, so now the question is, how does this thing we've invented play
> in with our current implementation of a class based object model and how
> does it meet developer preexisting expectations?

There are two ways to see it.  Either constructors are really just a
method that's called by the engine, or they are not a method and are
special "blocks" which are not callable in userland.  However, since I
can legally call `$obj->__construct()`, I think it's pretty safe to
say that it's considered a real method in PHP.  And real methods are
specifiable in abstract/interfaces.

So really we didn't invent anything at all.  The "invention" is that
the constructor is a method (with all the caveats that apply)...

> 3) In places that have no formal expectation and understanding in other
> programming languages, we've OFTEN favored *looseness over strictness*
>
> Even you Pierre, once promoted "looseness"
> http://news.php.net/php.internals/25089 (Pierre)

Well, looseness over strictness unless strictness is specified.  Look
at the class based type hints.  That's strict.  Interfaces and
signature checking are absolutely strict.  Considering that the use is
optional, and the construct that's using it is normally associated
with strictness that it's ok that the constructor check is strict...



Again, I'm not arguing the design decision of putting a constructor in
an interface.  I'm talking about what would be expected if you did, or
more specifically if you're allowed to...

---

## #56408 — Pierre Joye — 2011-11-18T19:02:44+00:00

URL: https://externals.io/message/56373#56408 · In reply to: #56404

On Fri, Nov 18, 2011 at 6:40 PM, Ralph Schindler
<ralph@ralphschindler.com> wrote:
> Hey Pierre,
>
> My perspective and expectations are framed by all sorts of existing
> literature as well as the discussions on this list.  It saddens me that you
> did not address any of the points I've brought up.  And, I simply cannot
> tell what basis you have for your interpretation and opinion. It seems more
> like you're basing your interpretation on preference alone.


Again, no, I do not base my opinion on personal preferences. I only do
not buy too much from the 'let do it the PHP way' when it comes to OO,
and yes I slightly move to the strict side.

> The facts are this:
>
> 1) What we know and have been told is that PHP's signature checking is
> governed by Liskov Substitution Principle.  There are many references to
> this in the list.

And for this exact case, it is correctly implemented as of now.

> 2) "Abstract Constructors" do not exist in any other language, for all
> intents and purposes, it's something we've invented:
>
> http://www.google.com/search?&q=%22abstract+constructor%22
>
> That's fine, so now the question is, how does this thing we've invented play
> in with our current implementation of a class based object model and how
> does it meet developer preexisting expectations?

A construct is a specialized method, that does not change a yota what
abstract methods are.

> Even you Pierre, once promoted "looseness"
> http://news.php.net/php.internals/25089 (Pierre)

Only the doom never changes their mind :-D


> 4) We should meet everyone's existing expectations, Rasmus talks about this:

We should meet consistency with standard behaviors and then it is easy
to learn, for everyone.

Cheers,
-- 
Pierre

@pierrejoye | http://blog.thepimp.net | http://www.libgd.org

---

## #56520 — Ralph Schindler — 2011-11-23T18:25:34+00:00

URL: https://externals.io/message/56373#56520 · In reply to: #56390

Internals:

Time to summarize.

It is clear to me that internals is divided on this issue.  I don't 
think it's a large enough issue to drag on, even when I disagree with it 
- both theoretically and in practice.

For most OO developer, putting ctors as an abstract or in an interface 
would not happen anyway, so this does not affect them.

** The current change represents a minor break in BC, that should be 
noted in the manual. **

Also, a decision needs to be made on what to do with grandchildren.  As 
I mentioned, the following produces no E_FATAL and no warnings:

   abstract class A {  abstract public function __construct($a, $b); }
   class B extends A { public function __construct($a, $b) {} }
   class C extends B { public function __construct(ArrayObject $d) {}

While this is correct behavior to me (ability for concrete to use its 
own ctor), using the *current logic* strict signature checking enforced 
from an abstract, then the above is also wrong.

** Can we decide what to do with that situation? **


> I strongly disagree, this encourages bad practices. We could however
> reduce the error level to warning.

I think this is a sufficient compromise- I don't see anything E_FATAL 
about a signature change in ctors (I actually see nothing wrong with it, 
but it's clear the community is divided there).

** Can we make that change? **


Thanks,
-ralph

---

## #56522 — Anthony Ferrara — 2011-11-23T18:37:02+00:00

URL: https://externals.io/message/56373#56522 · In reply to: #56520

Ralph:

From where I'm sitting, I can see a few sane alternatives (there may
be more, but here are the options I can see):

Option 1.  Remove signature checking from constructors all together.
(I don't care for this, but whatever).  Additionally, since it's not
enforced, perhaps an `E_DEPRECATED` or `E_STRICT` error should be raised
on definition, as it is superfluous...

Option 2.  Fix grandchild signature checking to be inline for how
signatures work with other methods.

Personally, I think option 2 is the better one.  I see it being odd
and inconsistent that all methods work one way, and constructors work
differently.  But that's just my feeling (and I know others disagree
there).

And please don't reduce the error level of a signature change (as it
would introduce even more inconsistency)...

Just my $0.02...

Anthony

On Wed, Nov 23, 2011 at 1:25 PM, Ralph Schindler
<ralph@ralphschindler.com> wrote:
> Internals:
>
> Time to summarize.
>
> It is clear to me that internals is divided on this issue.  I don't think
> it's a large enough issue to drag on, even when I disagree with it - both
> theoretically and in practice.
>
> For most OO developer, putting ctors as an abstract or in an interface would
> not happen anyway, so this does not affect them.
>
> ** The current change represents a minor break in BC, that should be noted
> in the manual. **
>
> Also, a decision needs to be made on what to do with grandchildren.  As I
> mentioned, the following produces no E_FATAL and no warnings:
>
>  abstract class A {  abstract public function __construct($a, $b); }
>  class B extends A { public function __construct($a, $b) {} }
>  class C extends B { public function __construct(ArrayObject $d) {}
>
> While this is correct behavior to me (ability for concrete to use its own
> ctor), using the *current logic* strict signature checking enforced from an
> abstract, then the above is also wrong.
>
> ** Can we decide what to do with that situation? **
>
> 
> > […]
>
> I think this is a sufficient compromise- I don't see anything E_FATAL about
> a signature change in ctors (I actually see nothing wrong with it, but it's
> clear the community is divided there).
>
> ** Can we make that change? **
>
>
> Thanks,
> -ralph

---

## #56567 — Richard Quadling — 2011-11-24T10:48:18+00:00

URL: https://externals.io/message/56373#56567 · In reply to: #56522

> Ralph:
>
> From where I'm sitting, I can see a few sane alternatives (there may
> be more, but here are the options I can see):
>
> Option 1.  Remove signature checking from constructors all together.
> (I don't care for this, but whatever).  Additionally, since it's not
> enforced, perhaps an `E_DEPRECATED` or `E_STRICT` error should be raised
> on definition, as it is superfluous...
>
> Option 2.  Fix grandchild signature checking to be inline for how
> signatures work with other methods.
>
> Personally, I think option 2 is the better one.  I see it being odd
> and inconsistent that all methods work one way, and constructors work
> differently.  But that's just my feeling (and I know others disagree
> there).
>
> And please don't reduce the error level of a signature change (as it
> would introduce even more inconsistency)...
>
> Just my $0.02...
>
> Anthony
>
> On Wed, Nov 23, 2011 at 1:25 PM, Ralph Schindler
> <ralph@ralphschindler.com> wrote:
> > […]

What is the normal way for userland developers to learn about
constructors? Do they know about LSP? If they do, does it apply to
constructors?

A comment on StackOverflow [1]

"At its heart LSP is about interfaces and contracts as well as how to
decided when to extend a class vs. use another strategy such as
composition to achieve your goal."

I am self taught. It was always my understanding that the constructor
was special in that it is, essentially, a magic method that can only
respond to the new keyword. Being able to call the constructor
directly, ..., that does feel a little odd as I can't actually
construct a new instance that way.
Using an interface to enforce the sig is fine. That's the exact nature
of an interface, to enforce the contract by design and if the
StackOverflow comment is accurate, then my understanding of interfaces
is fine with regard to LSP.

An abstract class, by its very nature is not formed. It isn't a
contract. It is an idea and the concrete doesn't need to fit
perfectly. OK. There is some things that are fixed, method signatures
most accept the parameters defined in the subclass but can add more
(as I understand things).

But is the signature of the constructor in an abstract class to be
enforced? I feel that it shouldn't be. It is a special method.

WikiPedia [2] has an article on Constructor Overloading. It says
"Constructors, used to create instances of an object, may also be
overloaded in some object oriented programming languages.". OK, so
WikiPedia may have a different opinion tomorrow.

Whilst we don't support overloading in the same way (I think we can
simulate it with __call() easily enough with ReflectionParameter being
my friend here maybe).

We, DO, provide the tools to allow overloading and non LSP coding
practises. Is it a great leap to also allow the same flexibility with
constructors?

Regards,

Richard Quadling.

[1] http://stackoverflow.com/questions/56860/what-is-the-liskov-substitution-principle
[2] http://en.wikipedia.org/wiki/Constructor_overloading#Constructor_overloading
-- 
Richard Quadling
Twitter : EE : Zend : PHPDoc : Fantasy Shopper
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY : bit.ly/lFnVea :
fan.sh/6/370

---

## #56574 — Anthony Ferrara — 2011-11-24T12:32:49+00:00

URL: https://externals.io/message/56373#56574 · In reply to: #56567

Something else to consider:

Right now, Constructors are checked on interfaces.  See the following
two examples:

http://codepad.viper-7.com/9IAGNP
http://codepad.viper-7.com/edokLi

So right now, interfaces are enforcing constructors fully (in 5.3).
Which makes more sense:  Having abstract methods behaving the same as
the interface declaration (to grand-children, etc), or having abstract
declarations behave differently and ignoring abstract constructors?

My vote is for consistency (since the concept between abstract methods
and interface methods is very similar)...

Anthony


> 
> > […]
>
> What is the normal way for userland developers to learn about
> constructors? Do they know about LSP? If they do, does it apply to
> constructors?
>
> A comment on StackOverflow [1]
>
> "At its heart LSP is about interfaces and contracts as well as how to
> decided when to extend a class vs. use another strategy such as
> composition to achieve your goal."
>
> I am self taught. It was always my understanding that the constructor
> was special in that it is, essentially, a magic method that can only
> respond to the new keyword. Being able to call the constructor
> directly, ..., that does feel a little odd as I can't actually
> construct a new instance that way.
> Using an interface to enforce the sig is fine. That's the exact nature
> of an interface, to enforce the contract by design and if the
> StackOverflow comment is accurate, then my understanding of interfaces
> is fine with regard to LSP.
>
> An abstract class, by its very nature is not formed. It isn't a
> contract. It is an idea and the concrete doesn't need to fit
> perfectly. OK. There is some things that are fixed, method signatures
> most accept the parameters defined in the subclass but can add more
> (as I understand things).
>
> But is the signature of the constructor in an abstract class to be
> enforced? I feel that it shouldn't be. It is a special method.
>
> WikiPedia [2] has an article on Constructor Overloading. It says
> "Constructors, used to create instances of an object, may also be
> overloaded in some object oriented programming languages.". OK, so
> WikiPedia may have a different opinion tomorrow.
>
> Whilst we don't support overloading in the same way (I think we can
> simulate it with __call() easily enough with ReflectionParameter being
> my friend here maybe).
>
> We, DO, provide the tools to allow overloading and non LSP coding
> practises. Is it a great leap to also allow the same flexibility with
> constructors?
>
> Regards,
>
> Richard Quadling.
>
> [1] http://stackoverflow.com/questions/56860/what-is-the-liskov-substitution-principle
> [2] http://en.wikipedia.org/wiki/Constructor_overloading#Constructor_overloading
> --
> Richard Quadling
> Twitter : EE : Zend : PHPDoc : Fantasy Shopper
> @RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY : bit.ly/lFnVea :
> fan.sh/6/370
