Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Current »

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 __set($name, $value) {
    throw new DomainException(
      pht(
        'Attempt to write to undeclared property %s::%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)));
  }
}

Related Tasks

  • No labels