KenLai
KenLai

Reputation: 251

PHP how to detect the change of variable?

Is PHP exists a function that detect the change of variable? That is something like this:

//called when $a is changed.
function variableChanged($value) {
    echo "value changed to " . $value;
}

$a = 1;
//attach the variable to the method.
$a.attachTo("variableChanged");
$a = 2;
$a = 3;

//expected output:
//value changed to 2
//value changed to 3

I know that it is easy to achieve if I use the "setter" method. But since I am working on some existing codes, I am not able to modify them. Can somebody tell me how to achieve my purpose? Thanks.

Upvotes: 2

Views: 12619

Answers (4)

Daniel W.
Daniel W.

Reputation: 32280

Besides using a debugger:

The SplObserver interface is used alongside SplSubject to implement the Observer Design Pattern. http://www.php.net/manual/en/class.splobserver.php

Or the magic methods __get() and __set(): Encapsulating the variable into a class, you could implement a event handler yourself and register the change of a variable. Also you could attach callbacks like here:

<?php
header("content-type: text/plain");

class WatchVar {
    private $data = array();
    private $org = array();
    private $callbacks = array();

    public function __set($name, $value) {
        if (!array_key_exists($name, $this->data)) {
            $this->org[$name] = $value;
        } else {
            //variable gets changed again!
            $this->triggerChangedEvent($name, $value);
        }
        $this->data[$name] = $value;
    }

    public function &__get($name) {
        if (array_key_exists($name, $this->data)) {
            if ($this->data[$name] != $this->org[$name]) {
                //variable has changed, return original
                //return $this->org[$name];
                //or return new state:
                return $this->data[$name];
            } else {
                //variable has not changed
                return $this->data[$name];
            }
        }
    }

    public function addCallback($name, $lambdaFunc) {
        $this->callbacks[$name] = $lambdaFunc;
    }

    protected function triggerChangedEvent($name, $value) {
        //$this->data[$name] has been changed!
        //callback call like:
        call_user_func($this->callbacks[$name], $value);
    }
}


$test = new WatchVar;
$test->addCallback('xxx', function($newValue) { echo "xxx has changed to {$newValue}\n"; });
$test->xxx = "aaa";

echo $test->xxx . "\n";
//output: aaa

$test->xxx = "bbb";
//output: xxx has changed to bbb

echo $test->xxx . "\n";
//output bbb

function messyFunction(&$var) {
    $var = "test";
}

messyFunction($test->xxx);
//output:

Upvotes: 1

Jhonathan H.
Jhonathan H.

Reputation: 2713

You could revised your code as simple like this just to produce that expected output you want.

function variableChanged($value) {
    return "value changed to " . $value;
    }

    $a = 1;

    echo $a = variableChanged(2);
    echo '<br/>';
    echo $a = variablechanged(3);

=================
//output
value changed to 2
value changed to 3

or using a class like this....

class VariableHandler{

        private $Variable;


        function setVariable($initialValue = NULL){
            $this->Variable = $initialValue;
            return $initialValue;
        }

        function changeValue($newValue = NULL){
            $this->Variable = $newValue;
            return "value has change to ". $newValue;
        }


    }

    $var = new VariableHandler;

    echo $a = $var->setVariable(1);
    echo '<br/>';
    echo $var->changeValue(2);
    echo '<br/>';
    echo $var->changeValue(3);

 =================
    //output
    value changed to 2
    value changed to 3

Upvotes: 1

bizzehdee
bizzehdee

Reputation: 21003

This could only be achieved by wrapping your variable within a class, and implementing a onchange yourself.

ie.

class MyVarContainer {
    var $internalVar = array();

    function __get($name) {
        return !empty($this->internalVar[$name]) $this->internalVar[$name] ? FALSE;
    }

    function __set($name, $value) {
       $oldval = $this->$name;
       $this->internalVar[$name] = $value;

       if($oldval !== FALSE) {
          onUpdated($name, $oldval, $value);
       } else {
          onCreated($name, $value);
       }
    }

    function onCreated($name, $value) {

    }

    function onUpdated($name, $oldvalue, $newvalue) {

    }
}

Upvotes: 3

Nanne
Nanne

Reputation: 64399

know that it is easy to achieve if I use the "setter" method. But since I am working on some existing codes, I am not able to modify them.

I assume that you can change some code, but not the object / class you are working with. If you cannot change any code at all this question would be useless.

What you can do is make your own class, extending the class you are working with, and adding your setter there. For all purposes you can not-override the parent setting, except for a magic setter on whatever you need to track. Track changes and then call the parent functions, so no changes in any other internal workings will be in effect.

Upvotes: 5

Related Questions