On 3/18/2016 11:10 PM, Dennis Birkholz wrote:
> Hi all,
> 
> Am 16.03.2016 um 21:29 schrieb Fleshgrinder:
>> Another more complicated user case would be *mysqli_fetch_object* that
>> populates the properties with values from a storage but values that
>> should become something specific and strict at some point but are
>> initially populated as strings. Type coercion would be a nice thing here
>> but with strict checks afterwards.
> 
> I really don't like the special way mysqli and PDO use here.
> Both should use the __set_state() magic method as would any userland code.
> But that is a discussion for another thread ;-)
> 
> Greets
> Dennis
> 

I think the discussion is important here because the introduction of
typed properties as proposed would break exactly this functionality of a
few of the most used extensions of all.

That being said, I agree and disagree at the same time with you on
*__set_state*. I also would prefer it if these methods would call
another method because they always require a check:

    final class A {
        private $x;
        private $y;

        private function __construct(O $x = null, O $y = null) {
            // mysqli_result::fetch_object
            // PDOStatement::fetchObject
            if (isset($this->x)) {
                $this->x = new O($this->x);
                $this->y = new O($this->y);
            }
            else {
                assert(isset($x));
                assert(isset($y));
                $this->x = $x;
                $this->y = $y;
            }
            // Some assertions on $x and $y ...
        }

        public static function new($x, $y, ErrorNotifier $n) {
            // Expensive validation ...
            return new static($x, $y);
        }

        public static function __set_state(array $data) {
            return new static($data['x'], $data['y']);
        }
    }

Of course there are other ways to implement this. I just want to
illustrate that it is not an ideal situation if we want to keep our code
as DRY as possible while using automated type checks without assertions.
But back to the *__set_state* problem. *__set_state* expects that the
members of the passed array are fully initialized because it is the
inverse of *var_export*. The data that is provided by
*mysqli_result::fetch_object* and *PDOStatement::fetchObject* are not
fully initialized so they are not good candidates to use *__set_state*.

Using another magic method would solve the riddle:

    final class A {

        private $x;
        private $y;

        private function __construct(O $x, O $y) {
            // Some assertions on $x and $y ...
            $this->x = $x;
            $this->y = $y;
        }

        public static function new($x, $y, ErrorNotifier $n) {
            // Expensive validation ...
            return new static($x, $y);
        }

        // mysqli_result::fetch_object
        // PDOStatement::fetchObject
        public static function __init_state(array $data) {
            return new static(new O($data['x']), new O($data['y']));
        }

        public static function __set_state(array $data) {
            return new static($data['x'], $data['y']);
        }
    }

Both examples might be bad but they are everything I just could come up
with.

TL;DR *__set_state* is not the correct method in this case because it is
the inverse of *var_export* and expects all members to be fully
initialized what is definitely not the case for both
*mysqli_result::fetch_object* and *PDOStatement::fetchObject*.

-- 
Richard "Fleshgrinder" Fussenegger

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to