1: <?php
2:
3: /**
4: * This file is part of the Nette Framework (https://nette.org)
5: *
6: * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
7: *
8: * For the full copyright and license information, please view
9: * the file license.txt that was distributed with this source code.
10: * @package Nette
11: */
12:
13:
14:
15: /**
16: * NObject is the ultimate ancestor of all instantiable classes.
17: *
18: * It defines some handful methods and enhances object core of PHP:
19: * - access to undeclared members throws exceptions
20: * - support for conventional properties with getters and setters
21: * - support for event raising functionality
22: * - ability to add new methods to class (extension methods)
23: *
24: * Properties is a syntactic sugar which allows access public getter and setter
25: * methods as normal object variables. A property is defined by a getter method
26: * and optional setter method (no setter method means read-only property).
27: * <code>
28: * $val = $obj->label; // equivalent to $val = $obj->getLabel();
29: * $obj->label = 'Nette'; // equivalent to $obj->setLabel('Nette');
30: * </code>
31: * Property names are case-sensitive, and they are written in the camelCaps
32: * or PascalCaps.
33: *
34: * Event functionality is provided by declaration of property named 'on{Something}'
35: * Multiple handlers are allowed.
36: * <code>
37: * public $onClick; // declaration in class
38: * $this->onClick[] = 'callback'; // attaching event handler
39: * if (!empty($this->onClick)) ... // are there any handlers?
40: * $this->onClick($sender, $arg); // raises the event with arguments
41: * </code>
42: *
43: * Adding method to class (i.e. to all instances) works similar to JavaScript
44: * prototype property. The syntax for adding a new method is:
45: * <code>
46: * NMyClass::extensionMethod('newMethod', function(MyClass $obj, $arg, ...) { ... });
47: * $obj = new MyClass;
48: * $obj->newMethod($x);
49: * </code>
50: *
51: * @author David Grudl
52: *
53: * @property-read string $class
54: * @property-read NClassReflection $reflection
55: * @package Nette
56: */
57: abstract class NObject
58: {
59:
60: /**
61: * @deprecated
62: */
63: public function getClass()
64: {
65: trigger_error(__METHOD__ . '() is deprecated; use getReflection()->getName() instead.', E_USER_WARNING);
66: return get_class($this);
67: }
68:
69:
70:
71: /**
72: * Access to reflection.
73: * @return NClassReflection
74: */
75: public function getReflection()
76: {
77: return new NClassReflection($this);
78: }
79:
80:
81:
82: /**
83: * Call to undefined method.
84: * @param string method name
85: * @param array arguments
86: * @return mixed
87: * @throws MemberAccessException
88: */
89: public function __call($name, $args)
90: {
91: return NObjectMixin::call($this, $name, $args);
92: }
93:
94:
95:
96: /**
97: * Call to undefined static method.
98: * @param string method name (in lower case!)
99: * @param array arguments
100: * @return mixed
101: * @throws MemberAccessException
102: */
103: public static function __callStatic($name, $args)
104: {
105: $class = __CLASS__;
106: throw new MemberAccessException("Call to undefined static method $class::$name().");
107: }
108:
109:
110:
111: /**
112: * Adding method to class.
113: * @param string method name
114: * @param mixed callback or closure
115: * @return mixed
116: */
117: public static function extensionMethod($name, $callback = NULL)
118: {
119: if (strpos($name, '::') === FALSE) {
120: $class = __CLASS__;
121: } else {
122: list($class, $name) = explode('::', $name);
123: }
124: $class = new NClassReflection($class);
125: if ($callback === NULL) {
126: return $class->getExtensionMethod($name);
127: } else {
128: $class->setExtensionMethod($name, $callback);
129: }
130: }
131:
132:
133:
134: /**
135: * Returns property value. Do not call directly.
136: * @param string property name
137: * @return mixed property value
138: * @throws MemberAccessException if the property is not defined.
139: */
140: public function &__get($name)
141: {
142: return NObjectMixin::get($this, $name);
143: }
144:
145:
146:
147: /**
148: * Sets value of a property. Do not call directly.
149: * @param string property name
150: * @param mixed property value
151: * @return void
152: * @throws MemberAccessException if the property is not defined or is read-only
153: */
154: public function __set($name, $value)
155: {
156: return NObjectMixin::set($this, $name, $value);
157: }
158:
159:
160:
161: /**
162: * Is property defined?
163: * @param string property name
164: * @return bool
165: */
166: public function __isset($name)
167: {
168: return NObjectMixin::has($this, $name);
169: }
170:
171:
172:
173: /**
174: * Access to undeclared property.
175: * @param string property name
176: * @return void
177: * @throws MemberAccessException
178: */
179: public function __unset($name)
180: {
181: throw new MemberAccessException("Cannot unset the property {$this->reflection->name}::\$$name.");
182: }
183:
184: }
185: