jeudi 28 mars 2019

I think I found a bug with setValue from ReflectionProperty

I'm working on a function to recursively remove arrays and objects recursively. The problem is that certain recursions may be inside private properties of objects.

below is what I tried as well as the entries I tried to use.

this is my entrie

class TestOBJ{

    private $fooClosure = null;
    public $bar = 5;
    private $myPrivateRecursion = null;
    private $aimArrayAndContainsRecursion = [];

    public function __construct()
    {
        $this->fooClosure = function(){
            echo 'pretty closure';
        };
    }

    public function setMyPrivateRecursion(&$obj){
        $this->myPrivateRecursion = &$obj;
    }

    public function setObjInsideArray(&$obj){
        $this->aimArrayAndContainsRecursion[] = &$obj;
    }
}

$std = new stdClass();
$std->std = 'any str';
$std->obj = new stdClass();
$std->obj->other = &$std;

$obj = new TestOBJ();
$obj->bar = new TestOBJ();
$obj->bar->bar = 'hey brow, please works';
$obj->bar->setMyPrivateRecursion($std);

my entrie is var $obj

and this is my function / solution

function makeRecursionStack($vector, &$stack = [], $from = null)
{
    if ($vector) {
        if (is_object($vector) && !in_array($vector, $stack, true) && !is_callable($vector)) {
            $stack[] = &$vector;
            if (get_class($vector) === 'stdClass') {
                foreach ($vector as $key => $value) {
                    if (in_array($vector->{$key}, $stack, true)) {
                        $vector->{$key} = null;
                    } else {
                        $vector->{$key} = $this->makeRecursionStack($vector->{$key}, $stack, $key);
                    }
                }
                return $vector;
            } else {
                $object = new \ReflectionObject($vector);
                $reflection = new \ReflectionClass($vector);
                $properties = $reflection->getProperties();
                if ($properties) {
                    foreach ($properties as $property) {
                        $property = $object->getProperty($property->getName());
                        $property->setAccessible(true);
                        if (!is_callable($property->getValue($vector))) {
                            $private = false;
                            if ($property->isPrivate()) {
                                $property->setAccessible(true);
                                $private = true;
                            }

                            if (in_array($property->getValue($vector), $stack, true)) {
                                $property->setValue($vector, null);
                            } else {
                                //if($property->getName() === 'myPrivateRecursion' && $from === 'bar'){
                                //$get = $property->getValue($vector);
                                //$set = $this->makeRecursionStack($get, $stack, $property->getName());                                
                                //$property->setValue($vector, $set);
                                //pre_clear_buffer_die($property->getValue($vector));
                                //}
                                $property->setValue($vector, $this->makeRecursionStack($property->getValue($vector), $stack, $property->getName()));
                            }

                            if ($private) {
                                $property->setAccessible(false);
                            }
                        }
                    }
                }
                return $vector;
            }
        } else if (is_array($vector)) {
            $nvector = [];
            foreach ($vector as $key => $value) {
                $nvector[$key] = $this->makeRecursionStack($value, $stack, $key);
            }
            return $nvector;
        } else {
            if (is_object($vector) && !is_callable($vector)) {
                return null;
            }
        }
    }
    return $vector;
}

The place where I have comments is where I noticed the problem. if the If is not commented there $get would receive a stdClass that has recursion and this works perfectly and $set would receive the stdClass without recursion. In that order.

$get =

$set =

After this lines

$property->setValue($vector, $set);
pre_clear_buffer_die($property->getValue($vector));

i obtain this

I try to put other value like an bool or null inside property and after set the $set but it's not works.

P.S: pre_clear_buffer_die kill php buffer, init other buffer and show var inside a <pre> after exit from script. Is an debugger function.





Aucun commentaire:

Enregistrer un commentaire