3

I have two Classes viz foo & Bar

class bar extends foo
{

    public $element = null;

    public function __construct()
    {
    }
}

and the Class foo goes as

class foo implements ArrayAccess
{

    private $data = [];
    private $elementId = null;

    public function __call($functionName, $arguments)
    {
        if ($this->elementId !== null) {
            echo "Function $functionName called with arguments " . print_r($arguments, true);
        }
        return true;
    }

    public function __construct($id = null)
    {
        $this->elementId = $id;
    }

    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->data[] = $value;
        } else {
            $this->data[$offset] = $value;
        }
    }

    public function offsetExists($offset)
    {
        return isset($this->data[$offset]);
    }

    public function offsetUnset($offset)
    {
        if ($this->offsetExists($offset)) {
            unset($this->data[$offset]);
        }
    }

    public function offsetGet($offset)
    {
        if (!$this->offsetExists($offset)) {
            $this->$offset = new foo($offset);
        }
    }
} 

i want that when i run the below piece of code:

$a = new bar();
$a['saysomething']->sayHello('Hello Said!');

should return Function sayHello Called with arguments Hello Said! from foo's __call magic method.

Here, i want to say is saysomething should be passed in $this->elementId from foo's __construct function and sayHello should be taken as method and Hello Said should be taken as parameters for sayHello Function which would be rendered from __call magic method.

Also, need to chain methods like:

$a['saysomething']->sayHello('Hello Said!')->sayBye('Good Bye!');

1 Answer 1

2

If I'm not mistaken, you should change foo::offsetGet() to this:

public function offsetGet($offset)
{
    if (!$this->offsetExists($offset)) {
        return new self($this->elementId);
    } else {
        return $this->data[$offset];
    }
}

It returns an instance of itself if there's no element at the given offset.

That said, foo::__construct() should be called from bar::__construct() as well and be passed a value other than null:

class bar extends foo
{

    public $element = null;

    public function __construct()
    {
        parent::__construct(42);
    }
}

Update

To chain calls, you need to return the instance from __call():

public function __call($functionName, $arguments)
{
    if ($this->elementId !== null) {
        echo "Function $functionName called with arguments " . print_r($arguments, true);
    }
    return $this;
}
Sign up to request clarification or add additional context in comments.

5 Comments

amazingly effective! Thanks a ton @Jack!
@Guns You're welcome; do note that $bar['saysomething'] doesn't return a bar object but a foo object.
thanks!. This works perfectly fine, however, when i chain methods it does not work. I am trying $a['saysomething']->sayHello['Hello Said!]->sayBye('Good Bye!');. How do i achieve this?
@Guns In that case, __call() must return $this; instead of return true;. Updated answer.
Wonderful! i wish i could give you 15-20 upvotes for this! Thanks a Ton @Jack

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.