Re: Re: 5dee3c11 break

From: Date: Wed, 07 May 2014 05:30:02 +0000
Subject: Re: Re: 5dee3c11 break
References: 1 2 3 4 5 6 7 8  Groups: php.internals 
Request: Send a blank email to internals+get-73993@lists.php.net to get a copy of this message
I think perhaps I haven't been clear in the past posts; I apologize. The
basic premise is that isset and empty should work the same on arrays as
they do on any array object. The problem comes from the fact that
offsetExists does not say that you should return false for an existing
offset with a null value.

At the end of this email is is a gauntlet of tests that *should work*, the
only exception is ExtendedArrayAccess which returns true for an existing
key with a null value (uses array_key_exists). I'd argue that
ExtendedArrayAccess uses the correct semantics and that all others should
be changed to not do the null check (only does it exist) but that would be
a big BC break. Hopefully this all makes sense.

<?php

class ExtendedArrayObject extends ArrayObject {
    function offsetExists($offset) {
        //echo "\t", __METHOD__, PHP_EOL;
        return parent::offsetExists($offset);
    }
    function offsetGet($offset) {
        //echo "\t", __METHOD__, PHP_EOL;
        return parent::offsetGet($offset);
    }
}

class ExtendedArrayAccess implements ArrayAccess {
    private $data = array();
    function __construct(array $array = array()) {
        $this->data = $array;
    }
    function offsetExists($offset) {
        return array_key_exists($offset, $this->data);
    }
    function offsetGet($offset) {
        return $this->data[$offset];
    }
    function offsetSet($offset, $value) {
        $this->data[$offset] = $value;
    }
    function offsetUnset($offset) {
        unset($this->data[$offset]);
    }
}

function createInputs() {
    return array(
        array(),
        new ArrayObject(),
        new ExtendedArrayObject(),
        new ExtendedArrayAccess(),
    );
}

class Tests {
    function isset_existing_key_with_not_empty_value($array) {
        $array['foo'] = 1;
        $this->expect(isset($array['foo']) === true, $array);
    }

    function empty_existing_key_with_not_empty_value($array) {
        $array['foo'] = 1;
        $this->expect(empty($array['foo']) === false, $array);
    }

    function isset_existing_key_with_empty_value($array) {
        $array['foo'] = 0;
        $this->expect(isset($array['foo']) === true, $array);
    }

    function empty_existing_key_with_empty_value($array) {
        $array['foo'] = 0;
        $this->expect(empty($array['foo']) === true, $array);
    }

    function isset_non_existent_key($array) {
        $this->expect(isset($array['foo']) === false, $array);
    }

    function empty_non_existent_key($array) {
        $this->expect(empty($array['foo']) === true, $array);
    }

    function isset_existing_key_with_null_value($array) {
        $array['foo'] = null;
        $this->expect(isset($array['foo']) === false, $array);
    }

    function empty_existing_key_with_null_value($array) {
        $array['foo'] = null;
        $this->expect(empty($array['foo']) === true, $array);
    }

    private function getType($v) {
       return is_array($v) ? 'array' : get_class($v);
    }

    private function expect($condition, $array) {
        if (!$condition) {
            echo "\t", $this->getType($array), ' failed ', PHP_EOL;
        }
    }
}

$tests = new Tests;
foreach (get_class_methods($tests) as $test) {
    echo "$test:", PHP_EOL;
    foreach (createInputs() as $structure) {
        $tests->$test($structure);
    }
    echo PHP_EOL;
}


Thread (17 messages)

« previous php.internals (#73993) next »