implementing-arrayaccess-for-domain-objects.rst 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. Implementing ArrayAccess for Domain Objects
  2. ===========================================
  3. .. sectionauthor:: Roman Borschel (roman@code-factory.org)
  4. This recipe will show you how to implement ArrayAccess for your
  5. domain objects in order to allow more uniform access, for example
  6. in templates. In these examples we will implement ArrayAccess on a
  7. `Layer Supertype <http://martinfowler.com/eaaCatalog/layerSupertype.html>`_
  8. for all our domain objects.
  9. Option 1
  10. --------
  11. In this implementation we will make use of PHPs highly dynamic
  12. nature to dynamically access properties of a subtype in a supertype
  13. at runtime. Note that this implementation has 2 main caveats:
  14. - It will not work with private fields
  15. - It will not go through any getters/setters
  16. .. code-block:: php
  17. <?php
  18. abstract class DomainObject implements ArrayAccess
  19. {
  20. public function offsetExists($offset) {
  21. return isset($this->$offset);
  22. }
  23. public function offsetSet($offset, $value) {
  24. $this->$offset = $value;
  25. }
  26. public function offsetGet($offset) {
  27. return $this->$offset;
  28. }
  29. public function offsetUnset($offset) {
  30. $this->$offset = null;
  31. }
  32. }
  33. Option 2
  34. --------
  35. In this implementation we will dynamically invoke getters/setters.
  36. Again we use PHPs dynamic nature to invoke methods on a subtype
  37. from a supertype at runtime. This implementation has the following
  38. caveats:
  39. - It relies on a naming convention
  40. - The semantics of offsetExists can differ
  41. - offsetUnset will not work with typehinted setters
  42. .. code-block:: php
  43. <?php
  44. abstract class DomainObject implements ArrayAccess
  45. {
  46. public function offsetExists($offset) {
  47. // In this example we say that exists means it is not null
  48. $value = $this->{"get$offset"}();
  49. return $value !== null;
  50. }
  51. public function offsetSet($offset, $value) {
  52. $this->{"set$offset"}($value);
  53. }
  54. public function offsetGet($offset) {
  55. return $this->{"get$offset"}();
  56. }
  57. public function offsetUnset($offset) {
  58. $this->{"set$offset"}(null);
  59. }
  60. }
  61. Read-only
  62. ---------
  63. You can slightly tweak option 1 or option 2 in order to make array
  64. access read-only. This will also circumvent some of the caveats of
  65. each option. Simply make offsetSet and offsetUnset throw an
  66. exception (i.e. BadMethodCallException).
  67. .. code-block:: php
  68. <?php
  69. abstract class DomainObject implements ArrayAccess
  70. {
  71. public function offsetExists($offset) {
  72. // option 1 or option 2
  73. }
  74. public function offsetSet($offset, $value) {
  75. throw new BadMethodCallException("Array access of class " . get_class($this) . " is read-only!");
  76. }
  77. public function offsetGet($offset) {
  78. // option 1 or option 2
  79. }
  80. public function offsetUnset($offset) {
  81. throw new BadMethodCallException("Array access of class " . get_class($this) . " is read-only!");
  82. }
  83. }