Read-only Class Properties in PHP

I’ve been writing PHP code for over 3 years now. Nearly every day, I learn a new “trick” with PHP. Often, those learning experiences start with a Google search, such as “Can I make class properties read-only in PHP?

The simple and short answer to that question is: No you cannot.

But the more accurate answer is: No you cannot. But you can fake it.

The Basic Class

Consider the most basic of class definitions. The class, shown below, has 2 properties and no methods.

<?PHP

class my_class_definition {
	public $my_dogs_name;
	public $my_other_dogs_name;

	public function __construct() {

	}
}
?>

Adding a little bit of complexity, you can create the same functionality with the following code.

<?PHP

class my_class {
	private $properties;

	public function __construct() {
		$this->properties = Array();
	}

	public function __set($property_name, $property_value) {
		$this->properties[$property_name] = $property_value;
	}
	public function __get($property_value) {
		return 
			(array_key_exists($property_name, $this->properties) 	? 
				$this->properties[$property_name] 	: 
				null );
	}
}
?>

Magic Methods

Note the two PHP magic methods, in the above block of code,

__set()

and

__get()

These two magic methods are called by PHP whenever you attempt to read from, or write to a non-existing or private property of an object.

With either class definition shown above, you can run the code below without triggering an error, even though the second class definition does not explicitly define the ‘my_dogs_name‘ and ‘my_other_dogs_name‘ properties.

$my_class = new my_class_definition();

$my_class->my_dogs_name = 'Luke';
$my_class->my_other_dogs_name = 'Cooper';

echo "I have two dogs, their names are "
   . "{$my_class->my_dogs_name} and "
   . "{$my_class->my_other_dogs_name}";

The output will look like this.

I have two dogs, their names are Luke and Cooper.

You can put any code that suits you inside the magic methods. Using these two magic methods, you can decide what constitutes a read-only property. It might be a property that’s set when the class is instantiated, or it might be anytime after it’s first set, or whatever you decide. As the developer, it’s your choice. But you have to figure out how you plan on enforcing that decision.

A Read-Only Example

Here’s an example of allowing a property to be set, but ignoring the ‘set’ when it’s already defined.

<?PHP

class my_class_definition {
	private $properties;
	private $read_only_properties;

	public function __construct($read_only_properties = Array()) {
		$this->properties = Array();
		if (is_array($read_only_properties)) {
			$this->read_only_properties = $read_only_properties;
		}
	}

	public function __set($property_name, $property_value) {
		if (array_search($property_name, $this->read_only_properties) && 
			isset($this->properties[$property_name] ) ) {
			error_log("Read-only property '{$property_name}' already set.");
		} else {
			$this->properties[$property_name] = $property_value;
		}
	}
	public function __get($property_value) {
		return 
			(array_key_exists($property_name, $this->properties) 	? 
				$this->properties[$property_name] 	: 
				null );
	}
}
$read_only_properties =
  [
	  'breed',
	  'sex',
	  'name',
	  'date_arrived',
	  'color',
  ];
$my_class = new my_class_definition($read_only_properties);

// First time property is set, it is accepted.
$my_class->breed = 'Golden Retriever';
$my_class->sex = 'Male';
$my_class->name = 'Luke';
$my_class->date_arrived = 'May 4, 2018';
$my_class->color = 'White';
$my_class->energy = 'High';

// Second time the properties are set, they are ignored, 
// because the properties are read-only
$my_class->name = 'Cooper';
$my_class->breed = 'Dachshund';

echo "My dog is {$my_class->name}. "
   . "He is a {$my_class->breed}. ";

?>

The echo at the bottom displays:

My dog is Luke. He is a Golden Retriever.

The lines….

$my_class->name = 'Cooper';
$my_class->breed = 'Dachshund';

….are ignored because the name and breed properties are already set and they are read-only.

Conclusion

The long answer is “Yes, you can make class properties read-only.” And PHP makes it easy. But would you really want to? That’s a question that only you can answer. To date, every time I’ve wanted to create a class with read-only properties, it was for some misguided purpose that when I actually started to design the code, I discovered that I didn’t need the class to protect me from myself. But I could have if I had needed to.

However, releasing code to the public may provide reasons to keep certain properties read-only. That could be used to enforce how a particular class is used.

© 2020, PaulSwarthout. All rights reserved.