# __set() / __get() : limitation and/or unintentional behavoiur?

- Thread: https://externals.io/message/22633
- Original archive: https://news-web.php.net/php.internals/22633
- Started by Jochem Maas on 2006-04-01T00:49:10+00:00
- Messages: 7
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #22633 — Jochem Maas — 2006-04-01T00:49:10+00:00

URL: https://externals.io/message/22633#22633

I ran the following code on 5.0.4 and 5.1.0 with identical results...

Could someone shed light one whether the observed behaviour is
intentional and/or correct?

I expected that one of the following would occur (which obviously doesn't :-):

1. the line commented with 'SET 2' would trigger a
call to __set() (which should fail?).

2. the key "test" would be set in the array returned
by __get() but not it the relevant array stored in
$this->array["insideArray"].

The reason I question whether what si observed below is wanted behaviour is
because I thought the __set() functionality was there to be able
to protect/control what stuffed into an object ... but apparently it's
rather easy to side step.

tia,
Jochem

<?php

class T {

     private $array = array();

     public function __get( $key ) {
     echo "Getting $key\n";
         return $this->array[$key];
     }

     public function __set( $key, $value ) {
     echo "Setting $key\n";
         $this->array[$key] = $value;
     }

}

$t = new T;

$t->insideArray = array(); 		// SET 1
$t->insideArray["test"] = "testing!";   // SET 2

var_dump( $t );

?>

OUTPUT:

Setting insideArray
Getting insideArray
object(T)#1 (1) {
   ["array:private"]=>
   array(1) {
     ["insideArray"]=>
     array(1) {
       ["test"]=>
       string(8) "testing!"
     }
   }

---

## #22635 — Unknown W. Brackets — 2006-04-01T07:05:56+00:00

URL: https://externals.io/message/22633#22635 · In reply to: #22633

The __set() method is called when a property of a class is set, __get() 
when a property is retrieved.

An array is simple a way of listing things; the array itself is a piece 
of data.  When you set a key in that array, you are not setting the 
array.  It may help to think of it like this:

$t = new T;

$t->insideClass = new T;

$t->insideClass->test = "testing!";

In this case, should __set() be called for both lines?  Or only for the 
first?  An array is exactly the same, except you cannot define a __set() 
method on it.

Anyway, I don't think this question belongs in internals, imho.

-[Unknown]

-------- Original Message --------

> I ran the following code on 5.0.4 and 5.1.0 with identical results...
> 
> Could someone shed light one whether the observed behaviour is
> intentional and/or correct?
> 
> I expected that one of the following would occur (which obviously 
> doesn't :-):
> 
> 1. the line commented with 'SET 2' would trigger a
> call to __set() (which should fail?).
> 
> 2. the key "test" would be set in the array returned
> by __get() but not it the relevant array stored in
> $this->array["insideArray"].
> 
> The reason I question whether what si observed below is wanted behaviour is
> because I thought the __set() functionality was there to be able
> to protect/control what stuffed into an object ... but apparently it's
> rather easy to side step.
> 
> tia,
> Jochem

---

## #22636 — Jochem Maas — 2006-04-01T08:13:05+00:00

URL: https://externals.io/message/22633#22636 · In reply to: #22635

Unknown W. Brackets wrote:
> The __set() method is called when a property of a class is set, __get() 
> when a property is retrieved.
> 
> An array is simple a way of listing things; the array itself is a piece 
> of data.  When you set a key in that array, you are not setting the 

I know these things.

> array.  It may help to think of it like this:

it's doesn't because object != array. as long as you stick to nesting objects
in this way everything is fine because __set() is called on the object
returned by __get() at the previous level - meaning control is maintained
by the object.

basically if I have an overloaded property that is an array I can bork it's
contents completely from outside of the object and the object doesn't get
anything to say about it.

medical analogy to observed behaviour:
if your liver was an array, then I could operate on your liver without you
ever knowing - heck I could remove it completely - regardless of any medical
training. can I assume you would rather keep control of who does what to your
liver?

> 
> $t = new T;
> 
> $t->insideClass = new T;
> 
> $t->insideClass->test = "testing!";
> 
> In this case, should __set() be called for both lines?  Or only for the 
> first?  

I'd expect that, __set() be called on $t in the first line and
on the second line __get() to be called on $t and __set() on
object $t->insideClass. assuming that class T is defined as in my previous
post.

> An array is exactly the same, except you cannot define a __set() 
> method on it.
> 
> Anyway, I don't think this question belongs in internals, imho.

I'm not asking how it works. or how to use it but whether it's intended.
(something which STFW or RTFM doesn't enlighten me about) which is why I ask
the people that wrote the functionality (I figure they would know what the
intention is/was).

let me guess, you think it belongs on php-generals? well I'm asking this
question based on a discussion held there - and nobody offered any kind of
answer ... in fact I justed checked and one of the other guys on the thread in
question (subject: "Overloading Limitation- Can Someone Confirm?") now has
a variation of the code we were playing with that segfaults in 5.0.4 and causes
a 'FATAL: emalloc()' error in 5.1.1 (I don't have a newer version at hand
but the other guy reports very odd behaviour in (I assume in 5.1.2) the code in
question is:

<?php

class T {

     private $array = array();

     public function __get( $key ) {
     echo "Getting $key\n";
         return $this->array[$key];
     }

     public function __set( $key, $value ) {
     echo "Setting $key\n";
         $this->array[$key] = $value;
     }

}

$t = new T;

$t->insideArray = array('a' => 'A', 'b' => 'B', 'c' => 'C');

foreach ($t->insideArray as $k => $v) {
     $t->insideArray[$k] = null;
}

if (count($t->insideArray) > 0) {
     foreach ($t->insideArray as $k => $v) {
         echo $v;
     }
}

var_dump($t);

?>


5.0.4 OUTPUT:
========================================
Setting insideArray
Getting insideArray
Getting insideArray
Getting insideArray
Getting insideArray
Getting insideArray
Segmentation fault

5.1.1 OUTPUT:
========================================
Setting insideArray
Getting insideArray
Getting insideArray
Getting insideArray
Getting insideArray
Getting insideArray
Getting insideArray
FATAL:  emalloc():  Unable to allocate 1916888421 bytes

I have sneaking suspicion that that's not meant to happen.

rgds,
Jochem

---

## #22637 — Matthew C. Kavanagh — 2006-04-01T08:41:53+00:00

URL: https://externals.io/message/22633#22637 · In reply to: #22636

Write your __set to not allow arrays to be set, and make arrays within 
your object private or objects with __set in their own right.

You could in fact create a "CustomArray" or something and allow 
CustomArrays to be __set'd in your object, then control their contents 
with CustomArray->__set().

There's no problem here.

---

## #22638 — Jochem Maas — 2006-04-01T17:04:09+00:00

URL: https://externals.io/message/22633#22638 · In reply to: #22637

Matthew C. Kavanagh wrote:
> Write your __set to not allow arrays to be set, and make arrays within 
> your object private or objects with __set in their own right.
> 
> You could in fact create a "CustomArray" or something and allow 
> CustomArrays to be __set'd in your object, then control their contents 
> with CustomArray->__set().
> 
> There's no problem here.

I don't even want to set arrays as overloaded properties and if I did
I could come up with another hundred workarounds to avoid the problem -
the ability to workaround a problem doesn't mean there is not a problem.

I posed the question after trying to help someone with a question posed
on php-generals ... and finding that the behaviour was actually rather strange
and unintuitive (imho);

Its still trivial to make php segfault when using __get()/__set() - I really
don't care what I do with php, a segfault should never occur, at worst I get
a nice FATAL ERROR telling what an idiot I have been... my tests with APC 3.0.10
show that despite the best efforts of mr. Lerdorf et al it is still segfaults
intermittently when using [lots of?] objects (of varying complexity) that use
__get()/__set()/__call()/etc - the last 24 hours lead me to suspect that not APC
but the engine itself is the 'bad guy' ...  unfortunately I don't have the C skills
to test that theory.

---

## #22639 — Wez Furlong — 2006-04-01T18:39:41+00:00

URL: https://externals.io/message/22633#22639 · In reply to: #22638

I suggest that you quit your bitching and start filing some solid bug
reports instead.
http://bugs.php.net

--Wez.


> Its still trivial to make php segfault when using __get()/__set() - I really
> don't care what I do with php, a segfault should never occur, at worst I get
> a nice FATAL ERROR telling what an idiot I have been... my tests with APC 3.0.10
> show that despite the best efforts of mr. Lerdorf et al it is still segfaults
> intermittently when using [lots of?] objects (of varying complexity) that use
> __get()/__set()/__call()/etc - the last 24 hours lead me to suspect that not APC
> but the engine itself is the 'bad guy' ...  unfortunately I don't have the C skills
> to test that theory.

---

## #22643 — Jasper Bryant-Greene — 2006-04-01T23:02:01+00:00

URL: https://externals.io/message/22633#22643 · In reply to: #22638

Jochem Maas wrote:
[snip]
> my tests with 
> APC 3.0.10
> show that despite the best efforts of mr. Lerdorf et al it is still 
> segfaults
> intermittently when using [lots of?] objects (of varying complexity) 
> that use
> __get()/__set()/__call()/etc - the last 24 hours lead me to suspect that 
> not APC
> but the engine itself is the 'bad guy' ...  unfortunately I don't have 
> the C skills
> to test that theory.
> 

Uh, no C skills required:

1. Disable APC
2. Test
3. If problem still occurs, APC is not the culprit

For crying out loud, if PHP is segfaulting then (assuming you didn't 
compile it with -fomg-really-fast-optimisation-thing) file a bug report!

-- 
Jasper Bryant-Greene
General Manager
Album Limited

http://www.album.co.nz/     0800 4 ALBUM
jasper@album.co.nz          021 708 334
