php magic method to catch array_push

2019-05-27 19:49发布

I am looking for a way to intercept the action in array_push, because when it will be retrieve it each value of the array has another info like:

class ClassName {

    var $test = array();

    function __set($attr, $value) {
      $this->$attr = 'My extra value'.$value;
    }    

    function index(){
      array_push($this->test, "some val");
      array_push($this->test, "some other val");

      print_r($this->test);

    }
}

$o = new ClassName();
$o->index();

And expected to get something like:

Array
(
    [0] => My extra value some val
    [1] => My extra value some other val
)

But i get:

Array
(
    [0] => some val
    [1] => some other val
)

Thanks to all

5条回答
Lonely孤独者°
2楼-- · 2019-05-27 20:30

To achieve what you're looking for, I suggest you create yourself a function that prefixes any value independent to it's use:

function prefix($value) {
    return 'My extra value '.$value;
}

You can then make use of that function inside the index() function:

function index()
{
    $test = array("some val", "some other val");
    foreach($test as $value)
    {
        $this->test[] = $this->prefix($value);
    }
    print_r($this->test);
}
查看更多
叼着烟拽天下
3楼-- · 2019-05-27 20:34

Instead of using an array, you can use a class that implements the ArrayAccess interface. This way you have full control over what occurs when you append to the array.

http://php.net/manual/en/class.arrayaccess.php

The drawback is that not all array functions will work on the object (ie sorting etc), but you can push like so:

$object[] = 'new value';

The alternative is to simply make a wrapper function for adding to the array.

public function addToArray($key, $value) {
   if ($key === null) {
      $this->test[] = 'My extra value ' . $value;
   } else {
      $this->test[$key] = 'My extra value ' . $value;
   }
}
查看更多
淡お忘
4楼-- · 2019-05-27 20:40

I don't totally understand what you're asking, but are you trying to do this:

$this->test['key'] = "some val";

That will allow you to setup your own output nicely. Because array_push() will throw on another nested level.

Update: Maybe something along these lines?

function push($prefix)
{
    $refl = new ReflectionClass($this);
    $prop = $refl->getProperties();
    foreach($prop as $p) {
        $this->{$p} = $prefix . $this->{$p};
    }
}
查看更多
爷、活的狠高调
5楼-- · 2019-05-27 20:45

The PHP manual says the following about magic methods:

__set() is run when writing data to inaccessible properties. (Emphasis mine)

Because the test property is inside the method and the function that is accessing it is inside the method, the function will see the variable directly and will not use the magic setter.

Additionally, even if you try to use array_push on the magic setter outside the class itself, that still will not work. You will get the error array_push() expects parameter 1 to be array, object given.

If you want to support array_push, you should write your own push($item) method:

function push($item) {
    $this->test[] = 'My extra value' . $item
}

or:

function push() {
    $items = func_get_args();

    // Using array_map is one of the many ways to do this.
    // You could also do it with a simpler `foreach` but I like this way.
    $prepend = function($item) {
        return 'My extra value' . $item;
    };
    $items = array_map($prepend, $items);
    array_push($this->test, $items);
}

if you want to support pushing multiple items at once.

查看更多
在下西门庆
6楼-- · 2019-05-27 20:56

From the PHP manual:

__set() is run when writing data to inaccessible properties.
__get() is utilized for reading data from inaccessible properties.

This is only called on reading/writing inaccessible properties. Your property however is public, which means it is accessible. Changing the access modifier to protected solves the issue.

Try this:

    class ClassName {

        private $test = array();

        public function __set($attr, $value) {
          $this->test[$attr] = $value;

        }    

        public function __get($attr) {
        return $this->test[$attr];
        }    

        public function index(){

          array_push($this->test, "some val");
          array_push($this->test, "some other val");

          return $this->test;

        }
    }

    $o = new ClassName();
    $o->setData = 'My extra value';
    print_r($o->index());
查看更多
登录 后发表回答