HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

Notify Property Changed

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
notifypropertychanged

Problem

Inspired by a SO post, just as an exercise, I tried to implement a way of notifying a consumer of a class about whether a property on an object has changed or not. I'm not attempting to use this in anyway, but I would like to learn from it.

interface INotifyPropertyChanged
{
    function PropertyChanged($name);
    function RegisterChangeCallback($callback);
}

abstract class NotifyPropertyChanged implements INotifyPropertyChanged
{
    public $changes;
    public $trackChanges;
    private $callback;

    public function PropertyChanged($name)
    {
        if( $this->callback != null){
            call_user_func($this->callback, $name);
        }

        if( !isset($this->changes))
            $this->changes = Array();

        if( !in_array($name, $this->changes))
            $this->changes[] = $name;
    }

    public function RegisterChangeCallback($callback) 
    { 
        $this->callback = $callback;
    }

    public function __set($name, $value) 
    { 
        $previousValue = $this->$name;
        $this->$name = $value;      

        if( $this->trackChanges && $previousValue !== $value) {         
            $this->PropertyChanged($name);
        }
    }

    public function __get($name) 
    { 
        return $this->$name;
    }
}


Then, implementing a class;

class SampleClass extends NotifyPropertyChanged
{
    protected $name;
}


And finally, usage;

$class = new SampleClass();
$class->name = "value";
$class->trackChanges = true;
$class->name = "test";
var_dump($class->changes);


And if you want, you can call $class->RegisterChangeCallback(..) to be told when it does change.

Like I said, I'm not planning on using this, it was an exercise to see if I could do something similar to .NETs INotifyPropertyChanged. And, what better way to get feedback on an idea.

Solution

First of all it is useless to use __set or __get if you're trying to access the non existing property that might also cause a cyclic request of the method. Instead you should have an array that contains the values now second thing if you will have the property inside the object the __set or __get methods won't be called. So you should fix those and it should work. If needed I will post a code with the fix

callback != null){
            call_user_func($this->callback, $name);
        }

        if( !isset($this->changes))
            $this->changes = Array();

        if( !in_array($name, $this->changes))
            $this->changes[$name][] = $this->$name;
    }

    public function RegisterChangeCallback($callback) 
    { 
        $this->callback = $callback;
    }

    public function __set($name, $value) 
    { 
        $previousValue = $this->$name;
        if( $this->trackChanges && $previousValue !== $value) {         
            $this->PropertyChanged($name);
        }
        $this->values[$name] = $value;      
    }

    public function __get($name) 
    { 
    if(array_key_exists($name,$this->values)){
        return $this->values[$name];
        }
        return null;
    }
}

class SampleClass extends NotifyPropertyChanged
{
}

$class = new SampleClass();
$class->name = "value";
$class->trackChanges = true;
$class->name = "test";
$class->name = "test2";
var_dump($class->changes);


the above code results which also allows you to have all changes

array(1) {
    ["name"]=>   
    array(2) {
        [0]=> 
        string(5) "value"
        [1]=> 
        string(4) "test"
    }
}

Code Snippets

<?php
interface INotifyPropertyChanged
{
    function PropertyChanged($name);
    function RegisterChangeCallback($callback);
}

abstract class NotifyPropertyChanged implements INotifyPropertyChanged
{
    public $changes;
    public $trackChanges;
    private $callback;
    protected $values = array();
    public function PropertyChanged($name)
    {
        if( $this->callback != null){
            call_user_func($this->callback, $name);
        }

        if( !isset($this->changes))
            $this->changes = Array();

        if( !in_array($name, $this->changes))
            $this->changes[$name][] = $this->$name;
    }

    public function RegisterChangeCallback($callback) 
    { 
        $this->callback = $callback;
    }

    public function __set($name, $value) 
    { 
        $previousValue = $this->$name;
        if( $this->trackChanges && $previousValue !== $value) {         
            $this->PropertyChanged($name);
        }
        $this->values[$name] = $value;      
    }

    public function __get($name) 
    { 
    if(array_key_exists($name,$this->values)){
        return $this->values[$name];
        }
        return null;
    }
}

class SampleClass extends NotifyPropertyChanged
{
}

$class = new SampleClass();
$class->name = "value";
$class->trackChanges = true;
$class->name = "test";
$class->name = "test2";
var_dump($class->changes);
array(1) {
    ["name"]=>   
    array(2) {
        [0]=> 
        string(5) "value"
        [1]=> 
        string(4) "test"
    }
}

Context

StackExchange Code Review Q#60052, answer score: 2

Revisions (0)

No revisions yet.