0

I have an issue with the following piece of code:

<?php
    class testClass
    {
        public $settings;

        public function __construct()
        {
            $this->settings = array(
                'paths' => array(
                    'protocol' => 'http'
                )
            );
        }

        public function getSomething()
        {
            $string = "settings['paths']['protocol']";

            echo $this->{$string};      /***** Line 19 *****/
        }
    }


    $obj = new testClass;
    $obj->getSomething();                          // Outputs a 'undefined' notice
    echo '<br />';
    echo $obj->settings['paths']['protocol'];      // Outputs http as expected
?>

This is a very basic example of the code I am employing, the actual code is more advanced, but the output / error produced is the same.

Basially, the class constructor populates a property with a settings array. The getSomething() method assigns an array path to a variable, which is then attempted to be retrieved by the echo $this->{$string}; code.

When I write: $obj->getSomething(); I get the following error:

Notice: Undefined property: testClass::$settings['paths']['protocol'] in /test.php on line 19

If I write the following code echo $obj->settings['paths']['protocol'] I get the expected http

I'm not sure why this isn't working!! If anyone can shed any light, it would be greatly appreciated.

Thanks

1 Answer 1

2

Well, you don't have a property called "settings['paths']['protocol']". You have a property called settings which has the key paths which has the key protocol. But PHP doesn't interpret $this->{$string} like copy and pasting code, it looks for a property called "settings['paths']['protocol']", which doesn't exist. That's nothing particular to OOP code, it's how any variable variable works.


I'd suggest something like this instead:

/**
 * Get settings, optionally filtered by path.
 *
 * @param string $path A path to a nested setting to be returned directly.
 * @return mixed The requested setting, or all settings if $path is null,
 *               or null if the path doesn't exist.
 */
public function get($path = null) {
    $value = $this->settings;

    foreach (array_filter(explode('.', $path)) as $key) {
        if (!is_array($value) || !isset($value[$key])) {
            return null;
        }
        $value = $value[$key];
    }

    return $value;
}

Called like this:

$obj->get('paths.protocol');

And just for fun, here a functional implementation of the above: ;-3

public function get($path = null) {
    return array_reduce(
        array_filter(explode('.', $path)),
        function ($value, $key) { return is_array($value) && isset($value[$key]) ? $value[$key] : null; },
        $this->settings
    );
}
Sign up to request clarification or add additional context in comments.

3 Comments

Do you know of any workarounds for this type of issue? Thanks for the explanation, I understand the problem now!
What exactly do you want to do? The example code hardly makes sense, since you wouldn't actually use it like that, I suppose.
Many thanks for the code fix! Its worked, and saved me much stress! Many thanks again.

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.