Skip to content

Commit 1f0abf2

Browse files
committed
prevent magic properties
1 parent 49f4081 commit 1f0abf2

File tree

4 files changed

+88
-0
lines changed

4 files changed

+88
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
v1.0.3 (2017-04)
2+
* prevent magic properties
3+
14
v1.0.2 (2017-04-11)
25
* prevent double constructor call
36

src/Value/AbstractValue.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,5 +225,17 @@ final public static function WrapOrNullArray (array &$array) {
225225
return $array;
226226
}
227227

228+
/**
229+
* Immutable objects cannot have any magic properties,
230+
* as they would be public and therefore changeable.
231+
* This method prevents setting any magic methods.
232+
*
233+
* @throws NoMagicPropertiesException (always)
234+
* @internal
235+
*/
236+
final public function __set ($name, $value) {
237+
throw new NoMagicPropertiesException ("immutable objects have no magic properties");
238+
}
239+
228240
}
229241

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
namespace mle86\Value;
3+
4+
class NoMagicPropertiesException
5+
extends \BadMethodCallException
6+
{
7+
}
8+

test/90-MagicPropertiesTest.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
namespace mle86\Value\Tests;
3+
4+
use mle86\Value\AbstractValue;
5+
use mle86\Value\Value;
6+
require_once 'helpers/TestWrapper4.php';
7+
8+
9+
/**
10+
* Ensures that AbstractValue instances
11+
* cannot have any magic properties.
12+
*
13+
* Implementors might still define public properties
14+
* (although they're not supposed to),
15+
* but we cannot really prevent that.
16+
*/
17+
class MagicPropertiesTest
18+
extends \PHPUnit_Framework_TestCase
19+
{
20+
21+
const VALID_VALUE = "41111";
22+
23+
/**
24+
* @return Value
25+
*/
26+
public function testInstance () {
27+
$tw = new TestWrapper4 (self::VALID_VALUE);
28+
29+
$this->assertTrue(($tw && $tw instanceof TestWrapper4 && $tw instanceof AbstractValue && $tw instanceof Value));
30+
$this->assertSame(self::VALID_VALUE, $tw->value());
31+
32+
return $tw;
33+
}
34+
35+
/**
36+
* @depends testInstance
37+
*/
38+
public function testSetMagicProperty (Value $o) {
39+
$prop = "magic_property_3453465110";
40+
$setto = 86;
41+
42+
$pv = (isset($o->{$prop})) ? $o->{$prop} : null;
43+
$this->assertNull($pv,
44+
"Newly-create object already has a magic property?!");
45+
46+
$e = null;
47+
try {
48+
$o->{$prop} = $setto;
49+
} catch (\Throwable $e) {
50+
// Good!
51+
// But we still need to check that property...
52+
}
53+
54+
$this->assertNotNull($e,
55+
"Setting a magic property did NOT result in an exception!");
56+
57+
$pv = (isset($o->{$prop})) ? $o->{$prop} : null;
58+
$this->assertNotEquals($setto, $pv,
59+
"Setting a magic property WORKED, despite throwing an exception!");
60+
$this->assertNull($pv,
61+
"Setting a magic property resulted in an exception, but also set the property to some unexpected value!");
62+
}
63+
64+
}
65+

0 commit comments

Comments
 (0)