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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: RQuadling at GMail dot com
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2025 The PHP Group
All rights reserved.
Last updated: Fri Jul 04 19:01:37 2025 UTC