PageRenderTime 76ms CodeModel.GetById 20ms RepoModel.GetById 2ms app.codeStats 0ms

/vendor/nette/nette/Nette/common/ObjectMixin.php

https://bitbucket.org/iiic/iszp
PHP | 247 lines | 123 code | 50 blank | 74 comment | 25 complexity | 78edd150d208d9246ea110494bc5815b MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (http://nette.org)
  4. *
  5. * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6. *
  7. * For the full copyright and license information, please view
  8. * the file license.txt that was distributed with this source code.
  9. */
  10. namespace Nette;
  11. use Nette;
  12. /**
  13. * Nette\Object behaviour mixin.
  14. *
  15. * @author David Grudl
  16. */
  17. final class ObjectMixin
  18. {
  19. /** @var array */
  20. private static $methods;
  21. /** @var array */
  22. private static $props;
  23. /**
  24. * Static class - cannot be instantiated.
  25. */
  26. final public function __construct()
  27. {
  28. throw new StaticClassException;
  29. }
  30. /**
  31. * __call() implementation.
  32. * @param object
  33. * @param string
  34. * @param array
  35. * @return mixed
  36. * @throws MemberAccessException
  37. */
  38. public static function call($_this, $name, $args)
  39. {
  40. $class = get_class($_this);
  41. $isProp = self::hasProperty($class, $name);
  42. if ($name === '') {
  43. throw new MemberAccessException("Call to class '$class' method without name.");
  44. } elseif ($isProp === 'event') { // calling event handlers
  45. if (is_array($_this->$name) || $_this->$name instanceof \Traversable) {
  46. foreach ($_this->$name as $handler) {
  47. Nette\Callback::create($handler)->invokeArgs($args);
  48. }
  49. } elseif ($_this->$name !== NULL) {
  50. throw new UnexpectedValueException("Property $class::$$name must be array or NULL, " . gettype($_this->$name) ." given.");
  51. }
  52. } elseif ($cb = Reflection\ClassType::from($_this)->getExtensionMethod($name)) { // extension methods
  53. array_unshift($args, $_this);
  54. return $cb->invokeArgs($args);
  55. } else {
  56. throw new MemberAccessException("Call to undefined method $class::$name().");
  57. }
  58. }
  59. /**
  60. * __call() implementation for entities.
  61. * @param object
  62. * @param string
  63. * @param array
  64. * @return mixed
  65. * @throws MemberAccessException
  66. */
  67. public static function callProperty($_this, $name, $args)
  68. {
  69. if (strlen($name) > 3) {
  70. $op = substr($name, 0, 3);
  71. $prop = strtolower($name[3]) . substr($name, 4);
  72. if ($op === 'add' && self::hasProperty(get_class($_this), $prop.'s')) {
  73. $_this->{$prop.'s'}[] = $args[0];
  74. return $_this;
  75. } elseif ($op === 'set' && self::hasProperty(get_class($_this), $prop)) {
  76. $_this->$prop = $args[0];
  77. return $_this;
  78. } elseif ($op === 'get' && self::hasProperty(get_class($_this), $prop)) {
  79. return $_this->$prop;
  80. }
  81. }
  82. return self::call($_this, $name, $args);
  83. }
  84. /**
  85. * __callStatic() implementation.
  86. * @param string
  87. * @param string
  88. * @param array
  89. * @return void
  90. * @throws MemberAccessException
  91. */
  92. public static function callStatic($class, $method, $args)
  93. {
  94. throw new MemberAccessException("Call to undefined static method $class::$method().");
  95. }
  96. /**
  97. * __get() implementation.
  98. * @param object
  99. * @param string property name
  100. * @return mixed property value
  101. * @throws MemberAccessException if the property is not defined.
  102. */
  103. public static function & get($_this, $name)
  104. {
  105. $class = get_class($_this);
  106. $uname = ucfirst($name);
  107. if (!isset(self::$methods[$class])) {
  108. self::$methods[$class] = array_flip(get_class_methods($class)); // public (static and non-static) methods
  109. }
  110. if ($name === '') {
  111. throw new MemberAccessException("Cannot read a class '$class' property without name.");
  112. } elseif (isset(self::$methods[$class][$m = 'get' . $uname]) || isset(self::$methods[$class][$m = 'is' . $uname])) { // property getter
  113. $val = $_this->$m();
  114. return $val;
  115. } elseif (isset(self::$methods[$class][$name])) { // public method as closure getter
  116. $val = Callback::create($_this, $name);
  117. return $val;
  118. } else { // strict class
  119. $type = isset(self::$methods[$class]['set' . $uname]) ? 'a write-only' : 'an undeclared';
  120. throw new MemberAccessException("Cannot read $type property $class::\$$name.");
  121. }
  122. }
  123. /**
  124. * __set() implementation.
  125. * @param object
  126. * @param string property name
  127. * @param mixed property value
  128. * @return void
  129. * @throws MemberAccessException if the property is not defined or is read-only
  130. */
  131. public static function set($_this, $name, $value)
  132. {
  133. $class = get_class($_this);
  134. $uname = ucfirst($name);
  135. if (!isset(self::$methods[$class])) {
  136. self::$methods[$class] = array_flip(get_class_methods($class));
  137. }
  138. if ($name === '') {
  139. throw new MemberAccessException("Cannot write to a class '$class' property without name.");
  140. } elseif (self::hasProperty($class, $name)) { // unsetted property
  141. $_this->$name = $value;
  142. } elseif (isset(self::$methods[$class][$m = 'set' . $uname])) { // property setter
  143. $_this->$m($value);
  144. } else { // strict class
  145. $type = isset(self::$methods[$class]['get' . $uname]) || isset(self::$methods[$class]['is' . $uname])
  146. ? 'a read-only' : 'an undeclared';
  147. throw new MemberAccessException("Cannot write to $type property $class::\$$name.");
  148. }
  149. }
  150. /**
  151. * __unset() implementation.
  152. * @param object
  153. * @param string property name
  154. * @return void
  155. * @throws MemberAccessException
  156. */
  157. public static function remove($_this, $name)
  158. {
  159. $class = get_class($_this);
  160. if (!self::hasProperty($class, $name)) { // strict class
  161. throw new MemberAccessException("Cannot unset the property $class::\$$name.");
  162. }
  163. }
  164. /**
  165. * __isset() implementation.
  166. * @param object
  167. * @param string property name
  168. * @return bool
  169. */
  170. public static function has($_this, $name)
  171. {
  172. $class = get_class($_this);
  173. $name = ucfirst($name);
  174. if (!isset(self::$methods[$class])) {
  175. self::$methods[$class] = array_flip(get_class_methods($class));
  176. }
  177. return $name !== '' && (isset(self::$methods[$class]['get' . $name]) || isset(self::$methods[$class]['is' . $name]));
  178. }
  179. /**
  180. * Checks if the public non-static property exists.
  181. * @return mixed
  182. */
  183. private static function hasProperty($class, $name)
  184. {
  185. $prop = & self::$props[$class][$name];
  186. if ($prop === NULL) {
  187. $prop = FALSE;
  188. try {
  189. $rp = new \ReflectionProperty($class, $name);
  190. if ($name === $rp->getName() && $rp->isPublic() && !$rp->isStatic()) {
  191. $prop = preg_match('#^on[A-Z]#', $name) ? 'event' : TRUE;
  192. }
  193. } catch (\ReflectionException $e) {}
  194. }
  195. return $prop;
  196. }
  197. }