Welcome! Log In Create A New Profile

Advanced

[PHP-DEV] Explicit constructor call and polymorphic dispatch

Posted by Tim Bezhashvyly 
Tim Bezhashvyly
[PHP-DEV] Explicit constructor call and polymorphic dispatch
January 12, 2017 08:20AM
Dear internals,

I would like to propose 2 RFCs:

- Disallow explicit call of __construct method
- Polymorphic dispatch

I'm sure I'm not the first who came with those 2 ideas so in case those were already proposed and rejected just let me know.

Otherwise please bless me with mana which will allow me to submit them.

Regards,
Tim
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Sebastian Bergmann
Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch
January 12, 2017 08:30AM
Am 12.01.2017 um 08:11 schrieb Tim Bezhashvyly:
> Disallow explicit call of __construct method

I am baffled that this (still) works:

$ cat /tmp/t.php
<?php
class C
{
public function __construct()
{
print __METHOD__ . PHP_EOL;
}
}

$o = new C;
$o->__construct();


$ php /tmp/t.php
C::__construct
C::__construct


$ php --version
PHP 7.1.0 (cli) (built: Dec 1 2016 07:39:00) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.1.0-dev, Copyright (c) 1998-2016 Zend Technologies

I am in favor of an RFC to disallow explicit invocation of interceptor
methods such as __construct().

Can we do this in PHP 7.2 or does this have to wait for PHP 8?

> Polymorphic dispatch

You mean dynamic dispatch of polymorphic methods, right?

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
On 1/12/2017 8:19 AM, Sebastian Bergmann wrote:
> Am 12.01.2017 um 08:11 schrieb Tim Bezhashvyly:
>> Disallow explicit call of __construct method
>
> I am baffled that this (still) works:
>
> $ cat /tmp/t.php
> <?php
> class C
> {
> public function __construct()
> {
> print __METHOD__ . PHP_EOL;
> }
> }
>
> $o = new C;
> $o->__construct();
>
>
> $ php /tmp/t.php
> C::__construct
> C::__construct
>
>
> $ php --version
> PHP 7.1.0 (cli) (built: Dec 1 2016 07:39:00) ( NTS )
> Copyright (c) 1997-2016 The PHP Group
> Zend Engine v3.1.0-dev, Copyright (c) 1998-2016 Zend Technologies
>
> I am in favor of an RFC to disallow explicit invocation of interceptor
> methods such as __construct().
>
> Can we do this in PHP 7.2 or does this have to wait for PHP 8?
>

https://github.com/php/php-langspec/blob/master/spec/14-classes.md#constructors

> Constructors are called by object-creation-expression and from within
> other (derived class) constructors.

This suggests that creation is possible via the `new` keyword only and
not via explicit calls to `__construct`. Hence, it could be categorized
as unspecified and dropped in 7.2.

However, there are other oddities that probably should be addressed too
in the context of constructors which are actually defined and thus can
only be removed in PHP 8.

> A constructor can return a result, by value or byRef.

> A constructor should not call its base-class constructor more than
> once.

```
<?php
// test.php

class A {

function __construct() {
echo __CLASS__ , "\n";
}

}

class B extends A {

function __construct() {
parent::__construct();
echo __CLASS__ , "\n";
parent::__construct();

return "PHP\n";
}

}

$b = new B;
echo $b->__construct();
```

```
$ php test.php
A
B
A
A
B
A
PHP
```

Note that both PHP and HHVM implement this _correctly_:

https://3v4l.org/DFGCa

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Heya,

While I agree that it is weird to be able to call constructors more than
once, this is generally used for:

* lazy loading
* resource reset

Specifically, what is going on is something like following:<?php

final class DbConnection
{
private $dsn;
private $initializer;
public function __construct(string $dsn)
{
$this->dsn = $dsn;
// socket stuff happens here, much like with PDO
}

public function query(string $queryString) : array
{
($this->initializer)();
// irrelevant from here on
return ['query' => $queryString, 'dsn' => $this->dsn];
}

public static function lazyInstance(string $dsn) : self
{
$instance = (new
ReflectionClass(self::class))->newInstanceWithoutConstructor();
$instance->initializer = function () use ($dsn, $instance) {
$instance->__construct($dsn);
$instance->initializer = function () {
};
};
return $instance;
}
}

$instance = DbConnection::lazyInstance('mysql://something');

var_dump($instance);

var_dump($instance->query('SELECT * FROM foo'));
var_dump($instance->query('SELECT * FROM bar'));

Here's an example of it at work: https://3v4l.org/Y0eoL

The pattern is simple:

* intercept constructor call
* capture constructor parameters
* instantiate without constructor
* defer constructor call for later

The same can be used in a myriad of different ways, but this is a legit
use-cases that generally don't involve coding everything into the same
class (and I generally advise against doing that anyway).

Therefore I don't see a reason to drop manual constructor calls, unless
there is a strong necessity to get rid of 'em.



Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/

On Thu, Jan 12, 2017 at 8:11 AM, Tim Bezhashvyly <tim.bezhashvyly@gmail.com>
wrote:

> Dear internals,
>
> I would like to propose 2 RFCs:
>
> - Disallow explicit call of __construct method
> - Polymorphic dispatch
>
> I'm sure I'm not the first who came with those 2 ideas so in case those
> were already proposed and rejected just let me know.
>
> Otherwise please bless me with mana which will allow me to submit them.
>
> Regards,
> Tim
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>
On 1/12/2017 9:35 PM, Marco Pivetta wrote:
> Heya,
>
> While I agree that it is weird to be able to call constructors more than
> once, this is generally used for:
>
> * lazy loading
> * resource reset
>
> Specifically, what is going on is something like following:<?php
>
> final class DbConnection
> {
> private $dsn;
> private $initializer;
> public function __construct(string $dsn)
> {
> $this->dsn = $dsn;
> // socket stuff happens here, much like with PDO
> }
>
> public function query(string $queryString) : array
> {
> ($this->initializer)();
> // irrelevant from here on
> return ['query' => $queryString, 'dsn' => $this->dsn];
> }
>
> public static function lazyInstance(string $dsn) : self
> {
> $instance = (new
> ReflectionClass(self::class))->newInstanceWithoutConstructor();
> $instance->initializer = function () use ($dsn, $instance) {
> $instance->__construct($dsn);
> $instance->initializer = function () {
> };
> };
> return $instance;
> }
> }
>
> $instance = DbConnection::lazyInstance('mysql://something');
>
> var_dump($instance);
>
> var_dump($instance->query('SELECT * FROM foo'));
> var_dump($instance->query('SELECT * FROM bar'));
>
> Here's an example of it at work: https://3v4l.org/Y0eoL
>
> The pattern is simple:
>
> * intercept constructor call
> * capture constructor parameters
> * instantiate without constructor
> * defer constructor call for later
>
> The same can be used in a myriad of different ways, but this is a legit
> use-cases that generally don't involve coding everything into the same
> class (and I generally advise against doing that anyway).
>
> Therefore I don't see a reason to drop manual constructor calls, unless
> there is a strong necessity to get rid of 'em.
>
>
>
> Marco Pivetta
>

Very creative but why not the following?

```
<?php

final class DbConnection {

private $dsn;

private $initialized = false;

public function __construct($dsn) {
$this->dsn = $dsn;
}

private function init() {
$this->initialized = true;

echo $this->dsn , "\n";
}

public function query($queryString) {
// this is actually cheaper than calling the closure
$this->initialized || $this->init();

return ['query' => $queryString, 'dsn' => $this->dsn];
}

}

$db_conn = new DbConnection('mysql://something');

var_dump(
$db_conn,
$db_conn->query('SELECT * FROM foo'),
$db_conn->query('SELECT * FROM bar')
);
```

https://3v4l.org/PaqqZ

Works equally well in PHP and HHVM and achieves your goal without using
undocumented side effects and reflection.

Adding the ability of a non-lazy and lazy construction is easily added
too if desired.

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hey Richard,

On Thu, Jan 12, 2017 at 9:58 PM, Fleshgrinder <php@fleshgrinder.com> wrote:

> On 1/12/2017 9:35 PM, Marco Pivetta wrote:
> > Heya,
> >
> > While I agree that it is weird to be able to call constructors more than
> > once, this is generally used for:
> >
> > * lazy loading
> > * resource reset
> >
> > Specifically, what is going on is something like following:<?php
> >
> > final class DbConnection
> > {
> > private $dsn;
> > private $initializer;
> > public function __construct(string $dsn)
> > {
> > $this->dsn = $dsn;
> > // socket stuff happens here, much like with PDO
> > }
> >
> > public function query(string $queryString) : array
> > {
> > ($this->initializer)();
> > // irrelevant from here on
> > return ['query' => $queryString, 'dsn' => $this->dsn];
> > }
> >
> > public static function lazyInstance(string $dsn) : self
> > {
> > $instance = (new
> > ReflectionClass(self::class))->newInstanceWithoutConstructor();
> > $instance->initializer = function () use ($dsn, $instance) {
> > $instance->__construct($dsn);
> > $instance->initializer = function () {
> > };
> > };
> > return $instance;
> > }
> > }
> >
> > $instance = DbConnection::lazyInstance('mysql://something');
> >
> > var_dump($instance);
> >
> > var_dump($instance->query('SELECT * FROM foo'));
> > var_dump($instance->query('SELECT * FROM bar'));
> >
> > Here's an example of it at work: https://3v4l.org/Y0eoL
> >
> > The pattern is simple:
> >
> > * intercept constructor call
> > * capture constructor parameters
> > * instantiate without constructor
> > * defer constructor call for later
> >
> > The same can be used in a myriad of different ways, but this is a legit
> > use-cases that generally don't involve coding everything into the same
> > class (and I generally advise against doing that anyway).
> >
> > Therefore I don't see a reason to drop manual constructor calls, unless
> > there is a strong necessity to get rid of 'em.
> >
> >
> >
> > Marco Pivetta
> >
>
> Very creative but why not the following?
>
> ```
> <?php
>
> final class DbConnection {
>
> private $dsn;
>
> private $initialized = false;
>
> public function __construct($dsn) {
> $this->dsn = $dsn;
> }
>
> private function init() {
> $this->initialized = true;
>
> echo $this->dsn , "\n";
> }
>
> public function query($queryString) {
> // this is actually cheaper than calling the closure
> $this->initialized || $this->init();
>
> return ['query' => $queryString, 'dsn' => $this->dsn];
> }
>
> }
>
> $db_conn = new DbConnection('mysql://something');
>
> var_dump(
> $db_conn,
> $db_conn->query('SELECT * FROM foo'),
> $db_conn->query('SELECT * FROM bar')
> );
> ```
>
> https://3v4l.org/PaqqZ
>
> Works equally well in PHP and HHVM and achieves your goal without using
> undocumented side effects and reflection.
>
> Adding the ability of a non-lazy and lazy construction is easily added
> too if desired.
>
> --
> Richard "Fleshgrinder" Fussenegger
>

I made an example where everything was in a single class, but most
scenarios involve a lazy-loading wrapper that has no knowledge of the
original class besides its constructor.

I use this approach to generate proxy classes that are "safe" to use with
fluent interfaces, for example (because fluent interfaces are really a mess
to work with).

The alternative (for me, specifically) is to copy the constructor AST into
a closure, then store the closure somewhere. Still, if that closure also
calls the private constructor, I have to do it recursively, and so on until
I just give up :-P Also, this assumes codegen. Large pieces of code will
need rewriting, whereas I don't see strong reasoning for dropping a feature
that, while weird, is actually useful.

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/
Tim Bezhashvyly
Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch
January 12, 2017 10:40PM
Hi Marco,

the only reason for prohibiting explicit __construct calls is that it makes PHP objects mutable and it's state unpredictable. Still would like to give this RFC a try.

And what about polymorphic dispatch?

Regards,
Tim

> On 12 Jan 2017, at 21:35, Marco Pivetta <ocramius@gmail.com> wrote:
>
> Heya,
>
> While I agree that it is weird to be able to call constructors more than once, this is generally used for:
>
> * lazy loading
> * resource reset
>
> Specifically, what is going on is something like following:<?php
>
> final class DbConnection
> {
> private $dsn;
> private $initializer;
> public function __construct(string $dsn)
> {
> $this->dsn = $dsn;
> // socket stuff happens here, much like with PDO
> }
>
> public function query(string $queryString) : array
> {
> ($this->initializer)();
> // irrelevant from here on
> return ['query' => $queryString, 'dsn' => $this->dsn];
> }
>
> public static function lazyInstance(string $dsn) : self
> {
> $instance = (new ReflectionClass(self::class))->newInstanceWithoutConstructor();
> $instance->initializer = function () use ($dsn, $instance) {
> $instance->__construct($dsn);
> $instance->initializer = function () {
> };
> };
> return $instance;
> }
> }
>
> $instance = DbConnection::lazyInstance('mysql://something');
>
> var_dump($instance);
>
> var_dump($instance->query('SELECT * FROM foo'));
> var_dump($instance->query('SELECT * FROM bar'));
>
> Here's an example of it at work: https://3v4l.org/Y0eoL https://3v4l.org/Y0eoL
>
> The pattern is simple:
>
> * intercept constructor call
> * capture constructor parameters
> * instantiate without constructor
> * defer constructor call for later
>
> The same can be used in a myriad of different ways, but this is a legit use-cases that generally don't involve coding everything into the same class (and I generally advise against doing that anyway).
>
> Therefore I don't see a reason to drop manual constructor calls, unless there is a strong necessity to get rid of 'em.
>
>
>
> Marco Pivetta
>
> http://twitter.com/Ocramius http://twitter.com/Ocramius
>
> http://ocramius.github.com/ http://ocramius.github.com/
>
> On Thu, Jan 12, 2017 at 8:11 AM, Tim Bezhashvyly <tim.bezhashvyly@gmail.com <mailto:tim.bezhashvyly@gmail.com>> wrote:
> Dear internals,
>
> I would like to propose 2 RFCs:
>
> - Disallow explicit call of __construct method
> - Polymorphic dispatch
>
> I'm sure I'm not the first who came with those 2 ideas so in case those were already proposed and rejected just let me know.
>
> Otherwise please bless me with mana which will allow me to submit them.
>
> Regards,
> Tim
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php http://www.php.net/unsub.php
>
>
On 1/12/2017 10:13 PM, Marco Pivetta wrote:
> Hey Richard,
>
> I made an example where everything was in a single class, but most
> scenarios involve a lazy-loading wrapper that has no knowledge of the
> original class besides its constructor.
>
> I use this approach to generate proxy classes that are "safe" to use with
> fluent interfaces, for example (because fluent interfaces are really a mess
> to work with).
>
> The alternative (for me, specifically) is to copy the constructor AST into
> a closure, then store the closure somewhere. Still, if that closure also
> calls the private constructor, I have to do it recursively, and so on until
> I just give up :-P Also, this assumes codegen. Large pieces of code will
> need rewriting, whereas I don't see strong reasoning for dropping a feature
> that, while weird, is actually useful.
>
> Marco Pivetta
>

That actually calls out for reflection and that's what it is good for.
Even if explicit construct calls are to be forbidden, the reflection API
is definitely a different story.

That being said, your remarks definitely tell everyone that a change in
this area -- if wanted -- is only possible in PHP 8 and has to be
considered a breaking change.

```
<?php

final class DbConnection {

private $dsn;

private $initializer;

public function __construct($dsn) {
$this->dsn = $dsn;
// socket stuff happens here, much like with PDO
}

public static function lazyInstance($dsn) {
$reflector = new ReflectionClass(self::class);
$self = $reflector->newInstanceWithoutConstructor();
$new = $reflector->getConstructor();

$self->initializer = function () use ($self, $new, $dsn) {
$new->invoke($self, $dsn);
$self->initializer = function () {};
};

return $self;
}

public function query($queryString) {
$this->initializer->__invoke();

// irrelevant from here on
return ['query' => $queryString, 'dsn' => $this->dsn];
}

}

$instance = DbConnection::lazyInstance('mysql://something');

var_dump($instance);

var_dump($instance->query('SELECT * FROM foo'));
var_dump($instance->query('SELECT * FROM bar'));
```

On 1/12/2017 10:34 PM, Tim Bezhashvyly wrote:
> the only reason for prohibiting explicit __construct calls is that it
> makes PHP objects mutable and it's state unpredictable. Still would
> like to give this RFC a try.
>

I completely share this concern with Tim. Of course reflection would
still allow one to circumvent any limitations imposed by the normal
runtime. But that's what reflection is for after all.

On 1/12/2017 10:34 PM, Tim Bezhashvyly wrote:
> And what about polymorphic dispatch?
>

I think you need to elaborate a bit more here to get some feedback.

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Tim Bezhashvyly
Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch
January 12, 2017 11:00PM
Hi Richard,

thank you for support with __construct. I absolutely agree that it breaks BC and fine to propose it just for PHP 8.

By polymorphic dispatch I mean a possibility to have the same method (including constructor) in multiple variations. E.g.:

class Price
{
public function __construct(int $price)
{
...
}

public function __construct(string $price)
{
...
}
}

Regards,
Tim

> On 12 Jan 2017, at 22:39, Fleshgrinder <php@fleshgrinder.com> wrote:
>
> On 1/12/2017 10:13 PM, Marco Pivetta wrote:
>> Hey Richard,
>>
>> I made an example where everything was in a single class, but most
>> scenarios involve a lazy-loading wrapper that has no knowledge of the
>> original class besides its constructor.
>>
>> I use this approach to generate proxy classes that are "safe" to use with
>> fluent interfaces, for example (because fluent interfaces are really a mess
>> to work with).
>>
>> The alternative (for me, specifically) is to copy the constructor AST into
>> a closure, then store the closure somewhere. Still, if that closure also
>> calls the private constructor, I have to do it recursively, and so on until
>> I just give up :-P Also, this assumes codegen. Large pieces of code will
>> need rewriting, whereas I don't see strong reasoning for dropping a feature
>> that, while weird, is actually useful.
>>
>> Marco Pivetta
>>
>
> That actually calls out for reflection and that's what it is good for.
> Even if explicit construct calls are to be forbidden, the reflection API
> is definitely a different story.
>
> That being said, your remarks definitely tell everyone that a change in
> this area -- if wanted -- is only possible in PHP 8 and has to be
> considered a breaking change.
>
> ```
> <?php
>
> final class DbConnection {
>
> private $dsn;
>
> private $initializer;
>
> public function __construct($dsn) {
> $this->dsn = $dsn;
> // socket stuff happens here, much like with PDO
> }
>
> public static function lazyInstance($dsn) {
> $reflector = new ReflectionClass(self::class);
> $self = $reflector->newInstanceWithoutConstructor();
> $new = $reflector->getConstructor();
>
> $self->initializer = function () use ($self, $new, $dsn) {
> $new->invoke($self, $dsn);
> $self->initializer = function () {};
> };
>
> return $self;
> }
>
> public function query($queryString) {
> $this->initializer->__invoke();
>
> // irrelevant from here on
> return ['query' => $queryString, 'dsn' => $this->dsn];
> }
>
> }
>
> $instance = DbConnection::lazyInstance('mysql://something');
>
> var_dump($instance);
>
> var_dump($instance->query('SELECT * FROM foo'));
> var_dump($instance->query('SELECT * FROM bar'));
> ```
>
> On 1/12/2017 10:34 PM, Tim Bezhashvyly wrote:
>> the only reason for prohibiting explicit __construct calls is that it
>> makes PHP objects mutable and it's state unpredictable. Still would
>> like to give this RFC a try.
>>
>
> I completely share this concern with Tim. Of course reflection would
> still allow one to circumvent any limitations imposed by the normal
> runtime. But that's what reflection is for after all.
>
> On 1/12/2017 10:34 PM, Tim Bezhashvyly wrote:
>> And what about polymorphic dispatch?
>>
>
> I think you need to elaborate a bit more here to get some feedback.
>
> --
> Richard "Fleshgrinder" Fussenegger


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hey Tim,

On Thu, Jan 12, 2017 at 10:51 PM, Tim Bezhashvyly <tim.bezhashvyly@gmail.com
> wrote:

> Hi Richard,
>
> thank you for support with __construct. I absolutely agree that it breaks
> BC and fine to propose it just for PHP 8.
>
> By polymorphic dispatch I mean a possibility to have the same method
> (including constructor) in multiple variations. E.g.:
>
> class Price
> {
> public function __construct(int $price)
> {
> ...
> }
>
> public function __construct(string $price)
> {
> ...
> }
> }
>
> Regards,
> Tim
>
> > On 12 Jan 2017, at 22:39, Fleshgrinder <php@fleshgrinder.com> wrote:
> >
> > On 1/12/2017 10:13 PM, Marco Pivetta wrote:
> >> Hey Richard,
> >>
> >> I made an example where everything was in a single class, but most
> >> scenarios involve a lazy-loading wrapper that has no knowledge of the
> >> original class besides its constructor.
> >>
> >> I use this approach to generate proxy classes that are "safe" to use
> with
> >> fluent interfaces, for example (because fluent interfaces are really a
> mess
> >> to work with).
> >>
> >> The alternative (for me, specifically) is to copy the constructor AST
> into
> >> a closure, then store the closure somewhere. Still, if that closure also
> >> calls the private constructor, I have to do it recursively, and so on
> until
> >> I just give up :-P Also, this assumes codegen. Large pieces of code will
> >> need rewriting, whereas I don't see strong reasoning for dropping a
> feature
> >> that, while weird, is actually useful.
> >>
> >> Marco Pivetta
> >>
> >
> > That actually calls out for reflection and that's what it is good for.
> > Even if explicit construct calls are to be forbidden, the reflection API
> > is definitely a different story.
> >
> > That being said, your remarks definitely tell everyone that a change in
> > this area -- if wanted -- is only possible in PHP 8 and has to be
> > considered a breaking change.
> >
> > ```
> > <?php
> >
> > final class DbConnection {
> >
> > private $dsn;
> >
> > private $initializer;
> >
> > public function __construct($dsn) {
> > $this->dsn = $dsn;
> > // socket stuff happens here, much like with PDO
> > }
> >
> > public static function lazyInstance($dsn) {
> > $reflector = new ReflectionClass(self::class);
> > $self = $reflector->newInstanceWithoutConstructor();
> > $new = $reflector->getConstructor();
> >
> > $self->initializer = function () use ($self, $new, $dsn) {
> > $new->invoke($self, $dsn);
> > $self->initializer = function () {};
> > };
> >
> > return $self;
> > }
> >
> > public function query($queryString) {
> > $this->initializer->__invoke();
> >
> > // irrelevant from here on
> > return ['query' => $queryString, 'dsn' => $this->dsn];
> > }
> >
> > }
> >
> > $instance = DbConnection::lazyInstance('mysql://something');
> >
> > var_dump($instance);
> >
> > var_dump($instance->query('SELECT * FROM foo'));
> > var_dump($instance->query('SELECT * FROM bar'));
> > ```
> >
> > On 1/12/2017 10:34 PM, Tim Bezhashvyly wrote:
> >> the only reason for prohibiting explicit __construct calls is that it
> >> makes PHP objects mutable and it's state unpredictable. Still would
> >> like to give this RFC a try.
> >>
> >
> > I completely share this concern with Tim. Of course reflection would
> > still allow one to circumvent any limitations imposed by the normal
> > runtime. But that's what reflection is for after all.
> >
> > On 1/12/2017 10:34 PM, Tim Bezhashvyly wrote:
> >> And what about polymorphic dispatch?
> >>
> >
> > I think you need to elaborate a bit more here to get some feedback.
> >
> > --
> > Richard "Fleshgrinder" Fussenegger
>
>
That's generally understood as "Method overloading". There were more
discussions about it in here recently: you might want to look them up.

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/
>
> I am baffled that this (still) works:
>

__clone was special cased in 5.x, but special case was removed in 7.0
means that previously you couldn't do publicly $obj->__clone(); now you can
and, yes, it's as dangerous as it looks
however, the special case was removed for a reason that i'm sure is a good
one, and i'm certain the same good reason is also valid for __construct

the only reason for prohibiting explicit __construct calls is that it makes
> PHP objects mutable


then don't call it explicitly, exactly like you wouldn't use reflection to
call private methods
On 1/13/2017 8:24 AM, Wes wrote:
>>
>> I am baffled that this (still) works:
>>
>
> __clone was special cased in 5.x, but special case was removed in 7.0
> means that previously you couldn't do publicly $obj->__clone(); now you can
> and, yes, it's as dangerous as it looks
> however, the special case was removed for a reason that i'm sure is a good
> one, and i'm certain the same good reason is also valid for __construct
>

What is the reason?

On 1/13/2017 8:24 AM, Wes wrote:
>> the only reason for prohibiting explicit __construct calls is that it makes
>> PHP objects mutable
>
>
> then don't call it explicitly, exactly like you wouldn't use reflection to
> call private methods
>

This is one possible answer to this issue. The question is whether PHP
wants to protect developers from errors and help reduce bugs by
enforcing things or wants to be a purely convention based language and
leave it developers to use it correctly.

I am completely in favor of #1 and you seem to be in favor of #2.

I actually have the impression that it is not defined which of both PHP
actually is or wants to be. The introduction of scalar type hints in PHP
7 definitely points towards #1 but it could just be an outlier.

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hi All.

Am 14.01.17 um 11:03 schrieb Fleshgrinder:
> On 1/13/2017 8:24 AM, Wes wrote:
[…]
> On 1/13/2017 8:24 AM, Wes wrote:
>>> the only reason for prohibiting explicit __construct calls is that it makes
>>> PHP objects mutable
>>
>>
>> then don't call it explicitly, exactly like you wouldn't use reflection to
>> call private methods
>>
>
> This is one possible answer to this issue. The question is whether PHP
> wants to protect developers from errors and help reduce bugs by
> enforcing things or wants to be a purely convention based language and
> leave it developers to use it correctly.
>
> I am completely in favor of #1 and you seem to be in favor of #2.
>
> I actually have the impression that it is not defined which of both PHP
> actually is or wants to be. The introduction of scalar type hints in PHP
> 7 definitely points towards #1 but it could just be an outlier.

Do we as "makers of PHP" want to dictate the user what the "intended"
behaviour of PHP is? Or are we treating the user as a responsible person
that knows what to do and also not to do?

Personally I'm in favour of the later. Let the user be able to call
__construct whenever they like. It's a special method which is clearly
visible by the two underscores at the start. So the users either know
exactly what they are doing or they need to learn it.

Translated to a different example this discussion is like: "Let's remove
the handle from the window because someone might be able to open the
window and jump out of it". The handle is there for a valid reason. And
as a window-maker I have no idea in what way it might be used. But I
have to accept that there are people missusing it. But should I limit
all those users with a valid use-case for it just to save some from
missusing it? And if we start with that, where should we stop?

Just my 0.02€

Cheers

Andreas
>


--
,,,
(o o)
+---------------------------------------------------------ooO-(_)-Ooo-+
| Andreas Heigl |
| mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" |
| http://andreas.heigl.org http://hei.gl/wiFKy7 |
+---------------------------------------------------------------------+
| http://hei.gl/root-ca |
+---------------------------------------------------------------------+
Attachments:
open | download - smime.p7s (2.4 KB)
On 1/14/2017 11:20 AM, Andreas Heigl wrote:
> Do we as "makers of PHP" want to dictate the user what the "intended"
> behaviour of PHP is? Or are we treating the user as a responsible person
> that knows what to do and also not to do?
>
> Personally I'm in favour of the later. Let the user be able to call
> __construct whenever they like. It's a special method which is clearly
> visible by the two underscores at the start. So the users either know
> exactly what they are doing or they need to learn it.
>
> Translated to a different example this discussion is like: "Let's remove
> the handle from the window because someone might be able to open the
> window and jump out of it". The handle is there for a valid reason. And
> as a window-maker I have no idea in what way it might be used. But I
> have to accept that there are people missusing it. But should I limit
> all those users with a valid use-case for it just to save some from
> missusing it? And if we start with that, where should we stop?
>
> Just my 0.02€
>
> Cheers
>
> Andreas
>

Yes, that is exactly the question. This needs to be voted on. Rust would
be an example that protects you and C/C++ would be examples that do not.
Both approaches are valid approaches.

Note that the dictation will not always work, this is why e.g. Rust has
unsafe blocks. The corresponding thing in PHP imho would be reflection.
Hence, if someone has a special case:

- Rust: use unsafe
- PHP: use reflection

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
> Am 14.01.2017 um 11:26 schrieb Fleshgrinder <php@fleshgrinder.com>:
>
>> On 1/14/2017 11:20 AM, Andreas Heigl wrote:
>> Do we as "makers of PHP" want to dictate the user what the "intended"
>> behaviour of PHP is? Or are we treating the user as a responsible person
>> that knows what to do and also not to do?
>>
>> Personally I'm in favour of the later. Let the user be able to call
>> __construct whenever they like. It's a special method which is clearly
>> visible by the two underscores at the start. So the users either know
>> exactly what they are doing or they need to learn it.
>>
>> Translated to a different example this discussion is like: "Let's remove
>> the handle from the window because someone might be able to open the
>> window and jump out of it". The handle is there for a valid reason. And
>> as a window-maker I have no idea in what way it might be used. But I
>> have to accept that there are people missusing it. But should I limit
>> all those users with a valid use-case for it just to save some from
>> missusing it? And if we start with that, where should we stop?
>>
>> Just my 0.02€
>>
>> Cheers
>>
>> Andreas
>>
>
> Yes, that is exactly the question. This needs to be voted on. Rust would
> be an example that protects you and C/C++ would be examples that do not.
> Both approaches are valid approaches.
>
> Note that the dictation will not always work, this is why e.g. Rust has
> unsafe blocks. The corresponding thing in PHP imho would be reflection.
> Hence, if someone has a special case:
>
> - Rust: use unsafe
> - PHP: use reflection
>
> --
> Richard "Fleshgrinder" Fussenegger

IMHO it already IS safe.

In PHP 4 the "constructor" was a method thad had the same name as the class. But now it is a class that has always the same name and is always preceded with two underscores. There is no way to "accidentaly" call that method. You have to explicitly call "__construct" to "break" things.

If developers "want" to break something they will find a way. Protecting "__construct" will not stop them from doing so. But it will stop the rest of us do legitimate things.

Cheers

Andreas

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Giovanni Giacobbi
Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch
January 14, 2017 04:00PM
I'm surprised no one is raising a strong argument about the
"parent::__construct()" call, so I'll do it.

I never liked typing "parent::__construct()" to call parent's class
constructor, but now that this proposal is being discussed (and might even
be accepted) I would like to throw some more meat to the fire:

<?php
class C {
function __construct($a) {
print "C::__construct() a=$a\n";
}
}
class D extends C {
function __construct($a, $b) {
parent::__construct($a, $b); // how it is now
// parent($a); // how i would like it
print "D::__construct() a=$a b=$b\n";
}
}
$d = new D(10, 20);

If you go for blocking explicit calls to __construct() (i'm personally in
favour of it), i hope you would change the syntax for its only legitimate
use which is calling the parent's constructor within a constructor, so how
about something like parent(...)?
It would be ugly to say "You are not supposed to explicit call
__construct() *ever*" and then "You know what, to initialize parent class
you need to call __construct()".

The construct method is called automagically when you instantiate the
class, I don't type something like $d = new D; $d->__construct(10, 20); so
I don't see why I should type that method name inside my derived
constructor. I just need a special syntax to do so.

And while I'm at it (a bit offtopic but related to my previous argument)
how about *not* requiring __construct() to be defined in the parent class?
I.e. when you call parent::__construct() if there is NO constructor defined
in the parent class just do nothing instead of going fatal error. I
*always* wanted this feature, because when you do "new C;" it doesn't go
fatal error if there is no __construct() defined. I don't think this is
breaking covariance if you assume that every class defines an empty
__construct() with no argument. I mean, if you later add an explicit
constructor to the parent class it *must* be without arguments unless you
accept you might break something.

Thanks!


On 14 January 2017 at 13:15, Andreas Heigl <andreas@heigl.org> wrote:

>
>
> > Am 14.01.2017 um 11:26 schrieb Fleshgrinder <php@fleshgrinder.com>:
> >
> >> On 1/14/2017 11:20 AM, Andreas Heigl wrote:
> >> Do we as "makers of PHP" want to dictate the user what the "intended"
> >> behaviour of PHP is? Or are we treating the user as a responsible person
> >> that knows what to do and also not to do?
> >>
> >> Personally I'm in favour of the later. Let the user be able to call
> >> __construct whenever they like. It's a special method which is clearly
> >> visible by the two underscores at the start. So the users either know
> >> exactly what they are doing or they need to learn it.
> >>
> >> Translated to a different example this discussion is like: "Let's remove
> >> the handle from the window because someone might be able to open the
> >> window and jump out of it". The handle is there for a valid reason. And
> >> as a window-maker I have no idea in what way it might be used. But I
> >> have to accept that there are people missusing it. But should I limit
> >> all those users with a valid use-case for it just to save some from
> >> missusing it? And if we start with that, where should we stop?
> >>
> >> Just my 0.02€
> >>
> >> Cheers
> >>
> >> Andreas
> >>
> >
> > Yes, that is exactly the question. This needs to be voted on. Rust would
> > be an example that protects you and C/C++ would be examples that do not..
> > Both approaches are valid approaches.
> >
> > Note that the dictation will not always work, this is why e.g. Rust has
> > unsafe blocks. The corresponding thing in PHP imho would be reflection.
> > Hence, if someone has a special case:
> >
> > - Rust: use unsafe
> > - PHP: use reflection
> >
> > --
> > Richard "Fleshgrinder" Fussenegger
>
> IMHO it already IS safe.
>
> In PHP 4 the "constructor" was a method thad had the same name as the
> class. But now it is a class that has always the same name and is always
> preceded with two underscores. There is no way to "accidentaly" call that
> method. You have to explicitly call "__construct" to "break" things.
>
> If developers "want" to break something they will find a way. Protecting
> "__construct" will not stop them from doing so. But it will stop the rest
> of us do legitimate things.
>
> Cheers
>
> Andreas
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>


--
Giovanni Giacobbi
Michał Brzuchalski
Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch
January 14, 2017 07:20PM
2017-01-14 15:58 GMT+01:00 Giovanni Giacobbi <giovanni@giacobbi.net>:

> I'm surprised no one is raising a strong argument about the
> "parent::__construct()" call, so I'll do it.
>
> I never liked typing "parent::__construct()" to call parent's class
> constructor, but now that this proposal is being discussed (and might even
> be accepted) I would like to throw some more meat to the fire:
>
> <?php
> class C {
> function __construct($a) {
> print "C::__construct() a=$a\n";
> }
> }
> class D extends C {
> function __construct($a, $b) {
> parent::__construct($a, $b); // how it is now
> // parent($a); // how i would like it
> print "D::__construct() a=$a b=$b\n";
> }
> }
> $d = new D(10, 20);
>
> If you go for blocking explicit calls to __construct() (i'm personally in
> favour of it), i hope you would change the syntax for its only legitimate
> use which is calling the parent's constructor within a constructor, so how
> about something like parent(...)?
>

AFAIK parent is a speciual scope which help refers to variables and
functions in base classe
http://php.net/manual/kr/keyword.parent.php
So it looks like proposing your syntax could lead to huge BC break.
In other languages (eg. Java) there is special syntax quite similar with
`super($a, $b)` call.



> It would be ugly to say "You are not supposed to explicit call
> __construct() *ever*" and then "You know what, to initialize parent class
> you need to call __construct()".
>
> The construct method is called automagically when you instantiate the
> class, I don't type something like $d = new D; $d->__construct(10, 20); so
> I don't see why I should type that method name inside my derived
> constructor. I just need a special syntax to do so.
>
> And while I'm at it (a bit offtopic but related to my previous argument)
> how about *not* requiring __construct() to be defined in the parent class?
> I.e. when you call parent::__construct() if there is NO constructor defined
> in the parent class just do nothing instead of going fatal error. I
> *always* wanted this feature, because when you do "new C;" it doesn't go
> fatal error if there is no __construct() defined. I don't think this is
> breaking covariance if you assume that every class defines an empty
> __construct() with no argument. I mean, if you later add an explicit
> constructor to the parent class it *must* be without arguments unless you
> accept you might break something.
>
> Thanks!
>
>
> On 14 January 2017 at 13:15, Andreas Heigl <andreas@heigl.org> wrote:
>
> >
> >
> > > Am 14.01.2017 um 11:26 schrieb Fleshgrinder <php@fleshgrinder.com>:
> > >
> > >> On 1/14/2017 11:20 AM, Andreas Heigl wrote:
> > >> Do we as "makers of PHP" want to dictate the user what the "intended"
> > >> behaviour of PHP is? Or are we treating the user as a responsible
> person
> > >> that knows what to do and also not to do?
> > >>
> > >> Personally I'm in favour of the later. Let the user be able to call
> > >> __construct whenever they like. It's a special method which is clearly
> > >> visible by the two underscores at the start. So the users either know
> > >> exactly what they are doing or they need to learn it.
> > >>
> > >> Translated to a different example this discussion is like: "Let's
> remove
> > >> the handle from the window because someone might be able to open the
> > >> window and jump out of it". The handle is there for a valid reason.
> And
> > >> as a window-maker I have no idea in what way it might be used. But I
> > >> have to accept that there are people missusing it. But should I limit
> > >> all those users with a valid use-case for it just to save some from
> > >> missusing it? And if we start with that, where should we stop?
> > >>
> > >> Just my 0.02€
> > >>
> > >> Cheers
> > >>
> > >> Andreas
> > >>
> > >
> > > Yes, that is exactly the question. This needs to be voted on. Rust
> would
> > > be an example that protects you and C/C++ would be examples that do
> not.
> > > Both approaches are valid approaches.
> > >
> > > Note that the dictation will not always work, this is why e.g. Rust has
> > > unsafe blocks. The corresponding thing in PHP imho would be reflection.
> > > Hence, if someone has a special case:
> > >
> > > - Rust: use unsafe
> > > - PHP: use reflection
> > >
> > > --
> > > Richard "Fleshgrinder" Fussenegger
> >
> > IMHO it already IS safe.
> >
> > In PHP 4 the "constructor" was a method thad had the same name as the
> > class. But now it is a class that has always the same name and is always
> > preceded with two underscores. There is no way to "accidentaly" call that
> > method. You have to explicitly call "__construct" to "break" things.
> >
> > If developers "want" to break something they will find a way. Protecting
> > "__construct" will not stop them from doing so. But it will stop the rest
> > of us do legitimate things.
> >
> > Cheers
> >
> > Andreas
> >
> > --
> > PHP Internals - PHP Runtime Development Mailing List
> > To unsubscribe, visit: http://www.php.net/unsub.php
> >
> >
>
>
> --
> Giovanni Giacobbi
>



--
regards / pozdrawiam,
--
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
On 1/14/2017 7:10 PM, Michał Brzuchalski wrote:
> AFAIK parent is a speciual scope which help refers to variables and
> functions in base classe
> http://php.net/manual/kr/keyword.parent.php
> So it looks like proposing your syntax could lead to huge BC break.
> In other languages (eg. Java) there is special syntax quite similar with
> `super($a, $b)` call.
>

`super` **is** Java’s `parent` keyword.

There is definitely no breaking change here by enabling `parent()` as an
alternative to `parent::__construct()` since it has no functionality at
all right now. As a matter of fact, PHP currently aborts with a fatal error:

```
Fatal error: Call to undefined function parent() in
```

Reversing keywords in the global scope is done regularly in PHP minor
versions, hence, that would not be a problem either.

I see only one single problem, users might expect that `parent()`
actually should call `parent::__invoke()`. However, that is not the case
right now and nobody ever asked for it plus it is a little used feature
anyways which does not require special treatment (imho).

Regarding the fatal error on a missing constructor implementation in the
parent. I fully agree that this should be possible.

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Michał Brzuchalski
Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch
January 14, 2017 10:10PM
2017-01-14 19:24 GMT+01:00 Fleshgrinder <php@fleshgrinder.com>:

> On 1/14/2017 7:10 PM, Michał Brzuchalski wrote:
> > AFAIK parent is a speciual scope which help refers to variables and
> > functions in base classe
> > http://php.net/manual/kr/keyword.parent.php
> > So it looks like proposing your syntax could lead to huge BC break.
> > In other languages (eg. Java) there is special syntax quite similar with
> > `super($a, $b)` call.
> >
>
> `super` **is** Java’s `parent` keyword.
>
> There is definitely no breaking change here by enabling `parent()` as an
> alternative to `parent::__construct()` since it has no functionality at
> all right now. As a matter of fact, PHP currently aborts with a fatal
> error:
>
> ```
> Fatal error: Call to undefined function parent() in
> ```
>
> Reversing keywords in the global scope is done regularly in PHP minor
> versions, hence, that would not be a problem either.
>
> I see only one single problem, users might expect that `parent()`
> actually should call `parent::__invoke()`. However, that is not the case
> right now and nobody ever asked for it plus it is a little used feature
> anyways which does not require special treatment (imho).
>
>
There might be different parent scope calls not only to magic method but
also all base class methods.


> Regarding the fatal error on a missing constructor implementation in the
> parent. I fully agree that this should be possible.
>
> --
> Richard "Fleshgrinder" Fussenegger
>



--
regards / pozdrawiam,
--
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
you guys went slightly off topic :P
Giovanni Giacobbi
Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch
January 15, 2017 12:50PM
You are right, I feel responsible for it (but proudly), as an excuse please
consider that the three topics covered have a certain dependancy:

Forbid __construct calls -> Forbid in constructor as well for coherency ->
need a new way to call parent's constructor
(bonus topic: implicit constructors)

It would be a pity if only the first part made it into the core, and I
personally like it plus I always wanted a better way to invoke parent's
constructor, so I threw it in the basket, but you are right, it is quite
off-topic. I'll check out the guide on how to submit RFCs so you guys can
fry me in another thread :P

On 15 January 2017 at 07:06, Wes <netmo.php@gmail.com> wrote:

> you guys went slightly off topic :P
>



--
Giovanni Giacobbi
Michał Brzuchalski
Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch
January 15, 2017 12:50PM
2017-01-15 12:41 GMT+01:00 Giovanni Giacobbi <giovanni@giacobbi.net>:

> You are right, I feel responsible for it (but proudly), as an excuse please
> consider that the three topics covered have a certain dependancy:
>
> Forbid __construct calls -> Forbid in constructor as well for coherency ->
> need a new way to call parent's constructor
> (bonus topic: implicit constructors)
>
>
I've talked with Fleshgrinder aside and I convinced using `parent($a, $b)`
as call for parent constructor fully satisfies me. Without any change to
`parent::`
scope resolution it's quite similar to Java's `super` which is also used as
parent
constructor and scope resolution.

So I'm +1 for `parent`


> It would be a pity if only the first part made it into the core, and I
> personally like it plus I always wanted a better way to invoke parent's
> constructor, so I threw it in the basket, but you are right, it is quite
> off-topic. I'll check out the guide on how to submit RFCs so you guys can
> fry me in another thread :P
>
> On 15 January 2017 at 07:06, Wes <netmo.php@gmail.com> wrote:
>
> > you guys went slightly off topic :P
> >
>
>
>
> --
> Giovanni Giacobbi
>



--
regards / pozdrawiam,
--
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
On 14/01/2017 14:58, Giovanni Giacobbi wrote:
> If you go for blocking explicit calls to __construct() (i'm personally in
> favour of it), i hope you would change the syntax for its only legitimate
> use which is calling the parent's constructor within a constructor, so how
> about something like parent(...)?
> It would be ugly to say "You are not supposed to explicit call
> __construct() *ever*" and then "You know what, to initialize parent class
> you need to call __construct()".

This is actually a very good point: if you ban calls to __construct, you
need syntax for not only calling the parent constructor, but other
constructors in the chain. For instance [https://3v4l.org/jTsek]:

<?php

class A
{
public function __construct() {
echo 'A';
}
}
class B extends A
{
public function __construct() {
parent::__construct();
echo 'B';
}
}
class C extends B
{
public function __construct() {
// Skip parent constructor, but call grand-parent
A::__construct();
echo 'C';
}
}
new C;


Probably you could say "cannot call __construct directly, except in the
__construct of a descendant class", but that all seems a bit fiddly.

I'm on the -1 side on this proposal, because the logical conclusion
would be that all magic methods should be banned: __clone was already
mentioned, but should you really be calling $foo->__get($bar) directly?
If so, why is that more legitimate than $foo->__construct? And if not,
do you allow parent::__get($bar), or do you insist on that using
different syntax as well? (If you think the answers are easy for __get,
pick a different magic method and ask the same questions).

These exceptions and special cases are going to proliferate, and all to
stop a hypothetical "misuse" of the language. Do you have an example of
a bug you've seen where a user acting reasonably would have been saved
by this new prohibition?

Regards,

--
Rowan Collins
[IMSoP]


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
We discussed this whole thing in different channels and together refined
the original idea as well as what the actual problem and a solution
would be.

The actual problem are multiple calls to the constructor because they
break the encapsulation. We know that there are many ways to do so but
this is a very weird one.

Hence, the proposal will be to disallow **multiple constructor calls**.
All examples that were given so far would continue to work. However, the
weird examples that were given at the beginning will stop working and
result in an error.

--
Richard "Fleshgrinder" Fussenegger

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Sorry, only registered users may post in this forum.

Click here to login