/
Disallow usage of undefined class properties [5.2.1]
Disallow usage of undefined class properties [5.2.1]
Currently it's possible to use class property that isn't even declared. This of course will produce no IDE auto-complete, but will work because PHP will declare such property dynamically.
It's considered bad practice because class declaration won't be exposing all it's properties. The solution from Phabricator is placing __set
and __get
methods in base class to ensure that in such cases an exception will the thrown. Example class: https://github.com/phacility/libphutil/blob/master/src/object/Phobject.php
<?php /** * Base class for libphutil objects. Enforces stricter object semantics than * PHP. * * When a program attempts to write to an undeclared object property, PHP * creates the property. However, in libphutil this is always an error (for * example, a misspelled property name). Instead of permitting the write, * subclasses will throw when an undeclared property is written. * * When a program attempts to iterate an object (for example, with `foreach`), * PHP iterates its public members. However, in libphutil this is always an * error (for example, iterating over the wrong variable). Instead of * permitting the iteration, subclasses will throw when an object is iterated. * * (Legitimately iterable subclasses can provide a working implementation of * Iterator instead.) */ abstract class Phobject implements Iterator { public function __get($name) { throw new DomainException( pht( 'Attempt to read from undeclared property %s.', get_class($this).'::'.$name)); } public function __set($name, $value) { throw new DomainException( pht( 'Attempt to write to undeclared property %s.', get_class($this).'::'.$name)); } public function current() { $this->throwOnAttemptedIteration(); } public function key() { $this->throwOnAttemptedIteration(); } public function next() { $this->throwOnAttemptedIteration(); } public function rewind() { $this->throwOnAttemptedIteration(); } public function valid() { $this->throwOnAttemptedIteration(); } private function throwOnAttemptedIteration() { throw new DomainException( pht( 'Attempting to iterate an object (of class %s) which is not iterable.', get_class($this))); } }