简体   繁体   中英

Retrieve class property value dynamically

I'm coming from a .Net background and I'm trying to wrap my brain around a programming pattern that I'm used to but in PHP.

I've got a class with an associative array property. I'd like to "elevate" some, but not all, of the associative array keys to class-level properties. In C# I'd normally do something like this:

//C# Code
class MyClass{
    private Dictionary<string, string> attributes = new Dictionary<string,string>();

    //Get/Set the ID from the private store
    public string ID{
        get { return (attributes.ContainsKey("ID") ? attributes["ID"] : "n/a"); }
        set { attributes.Add("ID", value); }
    }
}

This allows my object to control default values for missing properties. In PHP I couldn't find any way to do this directly. My first workaround was to just use functions:

//PHP Code
class MyClass{
  private $attributes = array();

  //Get the ID    
  public function getID(){
    return (array_key_exists('ID', $this->attributes) ? $this->attributes['ID'] : 'n/a');
  }
  //Set the ID
  public function setID($value){
    $this->attributes['ID'] = $value;
  }
}

This works although the calling syntax is slightly different and I've got two methods per property. Also, the code that is consuming these objects is currently inspecting object variables so functions wouldn't be found.

Then I started going down the magic method paths of __set and __get on the object itself and just switch case on the $name that's passed in and setting/getting my local variables. Unfortunately these methods don't get invoked if you modify the underlying array directly.

So my question is, is it possible in PHP to have a class-level property/variable that doesn't get calculated until it gets used?

PHP doesn't have properties as C# programmers would understand the concept, so you'll have to use methods as the getter and setter, but the principle is exactly the same.

class MyClass {
    private $attributes = array ();

    public function getSomeAttribute () {
        if (!array_key_exists ('SomeAttribute', $this -> attributes)) {
            // Do whatever you need to calculate the value of SomeAttribute here
            $this -> attributes ['SomeAttribute'] = 42;
        }
        return $this -> attributes ['SomeAttribute'];
    }
    // or if you just want a predictable result returned when the value isn't set yet
    public function getSomeAttribute () {
        return array_key_exists ('SomeAttribute', $this -> attributes)?
            $this -> attributes ['SomeAttribute']:
            'n/a';
    }

    public function setSomeAttribute ($value) {
        $this -> attributes ['SomeAttribute'] = $value;
    }
}

You essentially got the basic ideas right with your implementation, but it does mean a lot of "boilerplate" code. In theory you can avoid a lot of that with __get and __set, but I'd strongly advise against those as they can lead to epic amounts of confusion and nasty logical tangles like the "what happens if the value is set within the class instead of from outside?" issue that you've run into.

In PHP You can do something like this:

<?php
class MyClassWithoutParams{
    function test(){
      return $this->greeting . " " . $this->subject;
    }
}

$class = new MyClassWithoutParams();
$class->greeting = "Hello";
$class->subject = "world";

echo $class->greeting . " " . $class->subject . "<br />"; //Hello World
echo $class->test(). "<br />"; //Hello World
?>

You don't need to define any property, getter or setter to use properties. Of course it is better to do so, because it makes the code easier to read and allows autocomplete-functions of eclipse (or whatever IDE) to understand what you are looking for - but if you are just looking for the laziest way to implement an entity, that would work as well.

A more common approach would be to use an associative array instead of a class - but on arrays you cant define methods.

<?php
$array = new array();

$array["greeting"] = "Hello";
$array["subject"] = "World";

echo $array["greeting"] . " " . $array["subject"]; //Output: Hello World
?>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM