php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #55293 ArrayObject doesn't pass use offsetSet()
Submitted: 2011-07-27 12:09 UTC Modified: 2016-02-21 12:18 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: RQuadling at GMail dot com Assigned:
Status: Not a bug Package: Arrays related
PHP Version: 5.3.7RC3 OS: Windows XP SP3
Private report: No CVE-ID: None
 [2011-07-27 12:09 UTC] RQuadling at GMail dot com
Description:
------------
I while ago, I created a TypedArray class that restricted its contents to 
specific types by overriding the ArrayObject::offsetSet() method and applying 
type checking to the value being supplied.

This works fine if you create the arrayobject first and use conventional array 
appending code.

Today, I supplied the data as part of the constructor, had made a mistake in the 
type I wanted to restrict things to and no filtering of the type was applied.

I realised that calling the constructor for ArrayObject with data, doesn't pass 
the data through offsetSet(), so the override/filtering never took place.

Is this a bug?

The solution is to manually parse the array in the constructor.

Example below.

Test script:
---------------
<?php
class NoNumbersV1 extends ArrayObject {
  public function offsetSet($i_Offset, $m_Value) {
    if (!is_numeric($m_Value)) {
      parent::offsetSet($i_Offset, $m_Value);
    }
  }
}

class NoNumbersV2 extends ArrayObject {
  public function __construct($input = array(), $flags = 0, $iteratorClass = 'ArrayIterator') {
    parent::__construct(array(), $flags, $iteratorClass);
    foreach($input as $m_Key => $m_Value) {
      $this[$m_Key] = $m_Value;
    }
  }

  public function offsetSet($i_Offset, $m_Value) {
    if (!is_numeric($m_Value)) {
      parent::offsetSet($i_Offset, $m_Value);
    }
  }
}

$StringsV1 = new NoNumbersV1(array('One', 1, 'Two', 2, 'Three', 3));
$StringsV1[] = 'Four';
$StringsV1[] = 4;
$StringsV2 = new NoNumbersV2(array('One', 1, 'Two', 2, 'Three', 3));
$StringsV2[] = 'Four';
$StringsV2[] = 4;
print_r($StringsV1);
print_r($StringsV2);


Expected result:
----------------
NoNumbersV1 Object
(
    [storage:ArrayObject:private] => Array
        (
            [0] => One
            [2] => Two
            [4] => Three
            [5] => Four
        )

)
NoNumbersV2 Object
(
    [storage:ArrayObject:private] => Array
        (
            [0] => One
            [2] => Two
            [4] => Three
            [5] => Four
        )

)

Actual result:
--------------
NoNumbersV1 Object
(
    [storage:ArrayObject:private] => Array
        (
            [0] => One
            [1] => 1
            [2] => Two
            [3] => 2
            [4] => Three
            [5] => 3
            [6] => Four
        )

)
NoNumbersV2 Object
(
    [storage:ArrayObject:private] => Array
        (
            [0] => One
            [2] => Two
            [4] => Three
            [5] => Four
        )

)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-07-27 12:11 UTC] RQuadling at GMail dot com
OOI, I'm not really filtering on scalar types, but on interfaces.
 [2016-02-21 12:18 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2016-02-21 12:18 UTC] nikic@php.net
This is working as intended. Passing an array to exchangeArray() will not invoke offsetSet() either.

Essentially this is the difference between doing a $this->array = $array operation (what __construct and exchangeArray do) and a $this->array[$offset] = $value operation (what offsetSet is for).
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 18 09:01:27 2024 UTC