/libs/Nette/Utils/ObjectMixin.php

https://github.com/papousek/interlos-web · PHP · 178 lines · 87 code · 36 blank · 55 comment · 18 complexity · 92e1fe8d7c7c2c69c0dd7fff4ff8a19b MD5 · raw file

  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nette.org/license Nette license
  7. * @link http://nette.org
  8. * @category Nette
  9. * @package Nette
  10. */
  11. /**
  12. * Object behaviour mixin.
  13. *
  14. * @copyright Copyright (c) 2004, 2010 David Grudl
  15. * @package Nette
  16. */
  17. final class ObjectMixin
  18. {
  19. /** @var array */
  20. private static $methods;
  21. /**
  22. * Static class - cannot be instantiated.
  23. */
  24. final public function __construct()
  25. {
  26. throw new LogicException("Cannot instantiate static class " . get_class($this));
  27. }
  28. /**
  29. * Call to undefined method.
  30. * @param string method name
  31. * @param array arguments
  32. * @return mixed
  33. * @throws MemberAccessException
  34. */
  35. public static function call($_this, $name, $args)
  36. {
  37. $class = new ClassReflection($_this);
  38. if ($name === '') {
  39. throw new MemberAccessException("Call to class '$class->name' method without name.");
  40. }
  41. // event functionality
  42. if ($class->hasEventProperty($name)) {
  43. if (is_array($list = $_this->$name) || $list instanceof Traversable) {
  44. foreach ($list as $handler) {
  45. callback($handler)->invokeArgs($args);
  46. }
  47. }
  48. return NULL;
  49. }
  50. // extension methods
  51. if ($cb = $class->getExtensionMethod($name)) {
  52. array_unshift($args, $_this);
  53. return $cb->invokeArgs($args);
  54. }
  55. throw new MemberAccessException("Call to undefined method $class->name::$name().");
  56. }
  57. /**
  58. * Returns property value.
  59. * @param string property name
  60. * @return mixed property value
  61. * @throws MemberAccessException if the property is not defined.
  62. */
  63. public static function & get($_this, $name)
  64. {
  65. $class = get_class($_this);
  66. if ($name === '') {
  67. throw new MemberAccessException("Cannot read a class '$class' property without name.");
  68. }
  69. if (!isset(self::$methods[$class])) {
  70. // get_class_methods returns ONLY PUBLIC methods of objects
  71. // but returns static methods too (nothing doing...)
  72. // and is much faster than reflection
  73. // (works good since 5.0.4)
  74. self::$methods[$class] = array_flip(get_class_methods($class));
  75. }
  76. // property getter support
  77. $name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character
  78. $m = 'get' . $name;
  79. if (isset(self::$methods[$class][$m])) {
  80. // ampersands:
  81. // - uses &__get() because declaration should be forward compatible (e.g. with Html)
  82. // - doesn't call &$_this->$m because user could bypass property setter by: $x = & $obj->property; $x = 'new value';
  83. $val = $_this->$m();
  84. return $val;
  85. }
  86. $m = 'is' . $name;
  87. if (isset(self::$methods[$class][$m])) {
  88. $val = $_this->$m();
  89. return $val;
  90. }
  91. $name = func_get_arg(1);
  92. throw new MemberAccessException("Cannot read an undeclared property $class::\$$name.");
  93. }
  94. /**
  95. * Sets value of a property.
  96. * @param string property name
  97. * @param mixed property value
  98. * @return void
  99. * @throws MemberAccessException if the property is not defined or is read-only
  100. */
  101. public static function set($_this, $name, $value)
  102. {
  103. $class = get_class($_this);
  104. if ($name === '') {
  105. throw new MemberAccessException("Cannot assign to a class '$class' property without name.");
  106. }
  107. if (!isset(self::$methods[$class])) {
  108. self::$methods[$class] = array_flip(get_class_methods($class));
  109. }
  110. // property setter support
  111. $name[0] = $name[0] & "\xDF"; // case-sensitive checking, capitalize first character
  112. if (isset(self::$methods[$class]['get' . $name]) || isset(self::$methods[$class]['is' . $name])) {
  113. $m = 'set' . $name;
  114. if (isset(self::$methods[$class][$m])) {
  115. $_this->$m($value);
  116. return;
  117. } else {
  118. $name = func_get_arg(1);
  119. throw new MemberAccessException("Cannot assign to a read-only property $class::\$$name.");
  120. }
  121. }
  122. $name = func_get_arg(1);
  123. throw new MemberAccessException("Cannot assign to an undeclared property $class::\$$name.");
  124. }
  125. /**
  126. * Is property defined?
  127. * @param string property name
  128. * @return bool
  129. */
  130. public static function has($_this, $name)
  131. {
  132. if ($name === '') {
  133. return FALSE;
  134. }
  135. $class = get_class($_this);
  136. if (!isset(self::$methods[$class])) {
  137. self::$methods[$class] = array_flip(get_class_methods($class));
  138. }
  139. $name[0] = $name[0] & "\xDF";
  140. return isset(self::$methods[$class]['get' . $name]) || isset(self::$methods[$class]['is' . $name]);
  141. }
  142. }