Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • Configurator
  • Framework
  • LegacyObject

Traits

  • SmartObject
  • StaticClass

Exceptions

  • ArgumentOutOfRangeException
  • DeprecatedException
  • DirectoryNotFoundException
  • FileNotFoundException
  • InvalidArgumentException
  • InvalidStateException
  • IOException
  • MemberAccessException
  • NotImplementedException
  • NotSupportedException
  • OutOfRangeException
  • StaticClassException
  • UnexpectedValueException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette;
  9: 
 10: use Nette\Utils\Callback;
 11: use Nette\Utils\ObjectHelpers;
 12: use Nette\Utils\ObjectMixin;
 13: 
 14: 
 15: /**
 16:  * Strict class for better experience.
 17:  * - 'did you mean' hints
 18:  * - access to undeclared members throws exceptions
 19:  * - support for @property annotations
 20:  * - support for calling event handlers stored in $onEvent via onEvent()
 21:  * - compatible with Nette\Object
 22:  */
 23: trait SmartObject
 24: {
 25: 
 26:     /**
 27:      * @return mixed
 28:      * @throws MemberAccessException
 29:      */
 30:     public function __call($name, $args)
 31:     {
 32:         $class = get_class($this);
 33:         $isProp = ObjectHelpers::hasProperty($class, $name);
 34: 
 35:         if ($name === '') {
 36:             throw new MemberAccessException("Call to class '$class' method without name.");
 37: 
 38:         } elseif ($isProp === 'event') { // calling event handlers
 39:             if (is_array($this->$name) || $this->$name instanceof \Traversable) {
 40:                 foreach ($this->$name as $handler) {
 41:                     Callback::invokeArgs($handler, $args);
 42:                 }
 43:             } elseif ($this->$name !== null) {
 44:                 throw new UnexpectedValueException("Property $class::$$name must be array or null, " . gettype($this->$name) . ' given.');
 45:             }
 46: 
 47:         } elseif ($isProp && $this->$name instanceof \Closure) { // closure in property
 48:             trigger_error("Invoking closure in property via \$obj->$name() is deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED);
 49:             return call_user_func_array($this->$name, $args);
 50: 
 51:         } elseif (($methods = &ObjectMixin::getMethods($class)) && isset($methods[$name]) && is_array($methods[$name])) { // magic @methods
 52:             trigger_error("Magic methods such as $class::$name() are deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED);
 53:             list($op, $rp, $type) = $methods[$name];
 54:             if (count($args) !== ($op === 'get' ? 0 : 1)) {
 55:                 throw new InvalidArgumentException("$class::$name() expects " . ($op === 'get' ? 'no' : '1') . ' argument, ' . count($args) . ' given.');
 56: 
 57:             } elseif ($type && $args && !ObjectMixin::checkType($args[0], $type)) {
 58:                 throw new InvalidArgumentException("Argument passed to $class::$name() must be $type, " . gettype($args[0]) . ' given.');
 59:             }
 60: 
 61:             if ($op === 'get') {
 62:                 return $rp->getValue($this);
 63:             } elseif ($op === 'set') {
 64:                 $rp->setValue($this, $args[0]);
 65:             } elseif ($op === 'add') {
 66:                 $val = $rp->getValue($this);
 67:                 $val[] = $args[0];
 68:                 $rp->setValue($this, $val);
 69:             }
 70:             return $this;
 71: 
 72:         } elseif ($cb = ObjectMixin::getExtensionMethod($class, $name)) { // extension methods
 73:             trigger_error("Extension methods such as $class::$name() are deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED);
 74:             return Callback::invoke($cb, $this, ...$args);
 75: 
 76:         } else {
 77:             ObjectHelpers::strictCall($class, $name);
 78:         }
 79:     }
 80: 
 81: 
 82:     /**
 83:      * @return void
 84:      * @throws MemberAccessException
 85:      */
 86:     public static function __callStatic($name, $args)
 87:     {
 88:         ObjectHelpers::strictStaticCall(get_called_class(), $name);
 89:     }
 90: 
 91: 
 92:     /**
 93:      * @return mixed   property value
 94:      * @throws MemberAccessException if the property is not defined.
 95:      */
 96:     public function &__get($name)
 97:     {
 98:         $class = get_class($this);
 99:         $uname = ucfirst($name);
100: 
101:         if ($prop = ObjectMixin::getMagicProperty($class, $name)) { // property getter
102:             if (!($prop & 0b0001)) {
103:                 throw new MemberAccessException("Cannot read a write-only property $class::\$$name.");
104:             }
105:             $m = ($prop & 0b0010 ? 'get' : 'is') . $uname;
106:             if ($prop & 0b0100) { // return by reference
107:                 return $this->$m();
108:             } else {
109:                 $val = $this->$m();
110:                 return $val;
111:             }
112: 
113:         } elseif ($name === '') {
114:             throw new MemberAccessException("Cannot read a class '$class' property without name.");
115: 
116:         } elseif (($methods = &ObjectMixin::getMethods($class)) && isset($methods[$m = 'get' . $uname]) || isset($methods[$m = 'is' . $uname])) { // old property getter
117:             trigger_error("Use $m() or add annotation @property for $class::\$$name" . ObjectMixin::getSource(), E_USER_DEPRECATED);
118:             if ($methods[$m] === 0) {
119:                 $methods[$m] = (new \ReflectionMethod($class, $m))->returnsReference();
120:             }
121:             if ($methods[$m] === true) {
122:                 return $this->$m();
123:             } else {
124:                 $val = $this->$m();
125:                 return $val;
126:             }
127: 
128:         } elseif (isset($methods[$name])) { // public method as closure getter
129:             trigger_error("Accessing methods as properties via \$obj->$name is deprecated, use PHP callback [\$obj, '$name']" . ObjectMixin::getSource(), E_USER_DEPRECATED);
130:             $val = Callback::closure($this, $name);
131:             return $val;
132: 
133:         } elseif (isset($methods['set' . $uname])) { // property getter
134:             throw new MemberAccessException("Cannot read a write-only property $class::\$$name.");
135: 
136:         } else {
137:             ObjectHelpers::strictGet($class, $name);
138:         }
139:     }
140: 
141: 
142:     /**
143:      * @return void
144:      * @throws MemberAccessException if the property is not defined or is read-only
145:      */
146:     public function __set($name, $value)
147:     {
148:         $class = get_class($this);
149:         $uname = ucfirst($name);
150: 
151:         if (ObjectHelpers::hasProperty($class, $name)) { // unsetted property
152:             $this->$name = $value;
153: 
154:         } elseif ($prop = ObjectMixin::getMagicProperty($class, $name)) { // property setter
155:             if (!($prop & 0b1000)) {
156:                 throw new MemberAccessException("Cannot write to a read-only property $class::\$$name.");
157:             }
158:             $this->{'set' . $name}($value);
159: 
160:         } elseif ($name === '') {
161:             throw new MemberAccessException("Cannot write to a class '$class' property without name.");
162: 
163:         } elseif (($methods = &ObjectMixin::getMethods($class)) && isset($methods[$m = 'set' . $uname])) { // old property setter
164:             trigger_error("Use $m() or add annotation @property for $class::\$$name" . ObjectMixin::getSource(), E_USER_DEPRECATED);
165:             $this->$m($value);
166: 
167:         } elseif (isset($methods['get' . $uname]) || isset($methods['is' . $uname])) { // property setter
168:             throw new MemberAccessException("Cannot write to a read-only property $class::\$$name.");
169: 
170:         } else {
171:             ObjectHelpers::strictSet($class, $name);
172:         }
173:     }
174: 
175: 
176:     /**
177:      * @return void
178:      * @throws MemberAccessException
179:      */
180:     public function __unset($name)
181:     {
182:         $class = get_class($this);
183:         if (!ObjectHelpers::hasProperty($class, $name)) {
184:             throw new MemberAccessException("Cannot unset the property $class::\$$name.");
185:         }
186:     }
187: 
188: 
189:     /**
190:      * @return bool
191:      */
192:     public function __isset($name)
193:     {
194:         $uname = ucfirst($name);
195:         return ObjectMixin::getMagicProperty(get_class($this), $name)
196:             || ($name !== '' && ($methods = ObjectMixin::getMethods(get_class($this))) && (isset($methods['get' . $uname]) || isset($methods['is' . $uname])));
197:     }
198: 
199: 
200:     /**
201:      * @return Reflection\ClassType|\ReflectionClass
202:      * @deprecated
203:      */
204:     public static function getReflection()
205:     {
206:         trigger_error(get_called_class() . '::getReflection() is deprecated' . ObjectMixin::getSource(), E_USER_DEPRECATED);
207:         $class = class_exists(Reflection\ClassType::class) ? Reflection\ClassType::class : \ReflectionClass::class;
208:         return new $class(get_called_class());
209:     }
210: 
211: 
212:     /**
213:      * @return mixed
214:      * @deprecated use Nette\Utils\ObjectMixin::setExtensionMethod()
215:      */
216:     public static function extensionMethod($name, $callback = null)
217:     {
218:         if (strpos($name, '::') === false) {
219:             $class = get_called_class();
220:         } else {
221:             list($class, $name) = explode('::', $name);
222:             $class = (new \ReflectionClass($class))->getName();
223:         }
224:         trigger_error("Extension methods such as $class::$name() are deprecated" . ObjectMixin::getSource(), E_USER_DEPRECATED);
225:         if ($callback === null) {
226:             return ObjectMixin::getExtensionMethod($class, $name);
227:         } else {
228:             ObjectMixin::setExtensionMethod($class, $name, $callback);
229:         }
230:     }
231: }
232: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0