1

I need to share some associative data between different parts of my application with two requirements:

  • immutability (so read-only)
  • safety against mispelling or unavailable index inside the data
  • mixed type

I have no need for behaviour, internal state, validation or other DDD related features, just simple read-only data.

For the past I intensively used arrays for such situations but I feel they are more prone to errors due to possible mispelling (trying to access a non existent key would just trigger a notice in standard php configuration) and easy overwriting.

So I recently came to build up a simple class that stores an associative array of data but exposes one and only one way to access it, through php built-in magic methods, throwing exceptions for undefined index inside the data and preventing clients from writing it. Code follows:

class MyData
{

    protected $data;

    public function __construct(array $data) {
        $this->data = $data;
    }

    public function __get($propertyName) {

        if (!array_key_exists($propertyName, $this->data)) {
            throw new Exception("Missing key ".$propertyName);
        }

        return $this->data[$propertyName];
    }

    public function __set($propertyName, $value) {

        throw new Exception("Cannot write ".$propertyName);

    }

}

I think this approach would prevent from external writing and trying to access unavailable index, throwing related exceptions and notifying clients in a stronger way than a notice would do. Indeed this would throw an exception:

echo $data->propertyThatDoesNotExist;

and also this:

$data->propertyThatExists = $newValue;

I've already read about arrays vs objects for more or less specific purpose, such as:

I am curious about what some more experienced developers (even outside of php) think about this solution, thank you very much.

3
  • What are you specifically curious about? Can you ask a question in which the prima facie answer isn't "I like it" or "I don't like it"? Commented May 20, 2019 at 14:56
  • @RobertHarvey Is this a convenient approach that fulfills my requirements?
    – Sir_Faenor
    Commented May 20, 2019 at 21:31
  • Only you can answer that. Commented May 20, 2019 at 21:32

1 Answer 1

1

Your approach does not address spelling issues during development. Nor do you get any type hinting for your IDE. There is however a doc annotation that comes in handy:

/**
 * @property-read string $name
 * @property-read string $email
 * @property-read string $username
 */
class User
{
    public $name;
    public $email;
    public $username;

With this approach your IDE knows exactly which properties your class has and will flag spelling errors. It will also warn against any attempt to assign a value to a property outside of the class. Not quite as good as run time read-only protection but it works well for me. And of course it tells your IDE what the expected types are.

The doc property also works for properties accessed via __get($name). It basically restricts $name values and again provides type hints.

Just something to consider.

3
  • I did not know about that doc annotation, it's interesting even it's not runtime protection. Thanks!
    – Sir_Faenor
    Commented May 20, 2019 at 21:29
  • Since Cerad is defining public fields for the class instead of magic get/set functions, you get runtime protection as well. $user = new User(); $user->foo = 4; will throw a runtime error when attempting to assign the foo property. Commented Oct 17, 2019 at 16:55
  • @GregBurghardt I wish it worked that way but php itself has no readonly capability. Your IDE will complain. phpstorm gives you a nice red flag but the code will actually run just fine.
    – Cerad
    Commented Oct 17, 2019 at 17:41

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.