1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\PhpGenerator;
9:
10: use Nette;
11:
12:
13: 14: 15:
16: class Helpers
17: {
18: const PHP_IDENT = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
19: const MAX_DEPTH = 50;
20:
21:
22: 23: 24: 25:
26: public static function dump($var)
27: {
28: return self::_dump($var);
29: }
30:
31:
32: private static function _dump(& $var, $level = 0)
33: {
34: if ($var instanceof PhpLiteral) {
35: return (string) $var;
36:
37: } elseif (is_float($var)) {
38: if (is_finite($var)) {
39: $var = var_export($var, TRUE);
40: return strpos($var, '.') === FALSE ? $var . '.0' : $var;
41: }
42: return str_replace('.0', '', var_export($var, TRUE));
43:
44: } elseif (is_bool($var)) {
45: return $var ? 'TRUE' : 'FALSE';
46:
47: } elseif (is_string($var) && (preg_match('#[^\x09\x20-\x7E\xA0-\x{10FFFF}]#u', $var) || preg_last_error())) {
48: static $table;
49: if ($table === NULL) {
50: foreach (array_merge(range("\x00", "\x1F"), range("\x7F", "\xFF")) as $ch) {
51: $table[$ch] = '\x' . str_pad(dechex(ord($ch)), 2, '0', STR_PAD_LEFT);
52: }
53: $table['\\'] = '\\\\';
54: $table["\r"] = '\r';
55: $table["\n"] = '\n';
56: $table["\t"] = '\t';
57: $table['$'] = '\$';
58: $table['"'] = '\"';
59: }
60: return '"' . strtr($var, $table) . '"';
61:
62: } elseif (is_string($var)) {
63: return "'" . preg_replace('#\'|\\\\(?=[\'\\\\]|\z)#', '\\\\$0', $var) . "'";
64:
65: } elseif (is_array($var)) {
66: $space = str_repeat("\t", $level);
67:
68: static $marker;
69: if ($marker === NULL) {
70: $marker = uniqid("\x00", TRUE);
71: }
72: if (empty($var)) {
73: $out = '';
74:
75: } elseif ($level > self::MAX_DEPTH || isset($var[$marker])) {
76: throw new Nette\InvalidArgumentException('Nesting level too deep or recursive dependency.');
77:
78: } else {
79: $out = '';
80: $outAlt = "\n$space";
81: $var[$marker] = TRUE;
82: $counter = 0;
83: foreach ($var as $k => & $v) {
84: if ($k !== $marker) {
85: $item = ($k === $counter ? '' : self::_dump($k, $level + 1) . ' => ') . self::_dump($v, $level + 1);
86: $counter = is_int($k) ? max($k + 1, $counter) : $counter;
87: $out .= ($out === '' ? '' : ', ') . $item;
88: $outAlt .= "\t$item,\n$space";
89: }
90: }
91: unset($var[$marker]);
92: }
93: return 'array(' . (strpos($out, "\n") === FALSE && strlen($out) < 40 ? $out : $outAlt) . ')';
94:
95: } elseif ($var instanceof \Serializable) {
96: $var = serialize($var);
97: return 'unserialize(' . self::_dump($var, $level) . ')';
98:
99: } elseif ($var instanceof \Closure) {
100: throw new Nette\InvalidArgumentException('Cannot dump closure.');
101:
102: } elseif (is_object($var)) {
103: if (PHP_VERSION_ID >= 70000 && ($rc = new \ReflectionObject($var)) && $rc->isAnonymous()) {
104: throw new Nette\InvalidArgumentException('Cannot dump anonymous class.');
105: }
106: $arr = (array) $var;
107: $space = str_repeat("\t", $level);
108: $class = get_class($var);
109:
110: static $list = array();
111: if ($level > self::MAX_DEPTH || in_array($var, $list, TRUE)) {
112: throw new Nette\InvalidArgumentException('Nesting level too deep or recursive dependency.');
113:
114: } else {
115: $out = "\n";
116: $list[] = $var;
117: if (method_exists($var, '__sleep')) {
118: foreach ($var->__sleep() as $v) {
119: $props[$v] = $props["\x00*\x00$v"] = $props["\x00$class\x00$v"] = TRUE;
120: }
121: }
122: foreach ($arr as $k => & $v) {
123: if (!isset($props) || isset($props[$k])) {
124: $out .= "$space\t" . self::_dump($k, $level + 1) . ' => ' . self::_dump($v, $level + 1) . ",\n";
125: }
126: }
127: array_pop($list);
128: $out .= $space;
129: }
130: return $class === 'stdClass'
131: ? "(object) array($out)"
132: : __CLASS__ . "::createObject('$class', array($out))";
133:
134: } elseif (is_resource($var)) {
135: throw new Nette\InvalidArgumentException('Cannot dump resource.');
136:
137: } else {
138: return var_export($var, TRUE);
139: }
140: }
141:
142:
143: 144: 145: 146:
147: public static function format($statement)
148: {
149: $args = func_get_args();
150: return self::formatArgs(array_shift($args), $args);
151: }
152:
153:
154: 155: 156: 157:
158: public static function formatArgs($statement, array $args)
159: {
160: $a = strpos($statement, '?');
161: while ($a !== FALSE) {
162: if (!$args) {
163: throw new Nette\InvalidArgumentException('Insufficient number of arguments.');
164: }
165: $arg = array_shift($args);
166: if (substr($statement, $a + 1, 1) === '*') {
167: if (!is_array($arg)) {
168: throw new Nette\InvalidArgumentException('Argument must be an array.');
169: }
170: $s = substr($statement, 0, $a);
171: $sep = '';
172: foreach ($arg as $tmp) {
173: $s .= $sep . self::dump($tmp);
174: $sep = strlen($s) - strrpos($s, "\n") > 100 ? ",\n\t" : ', ';
175: }
176: $statement = $s . substr($statement, $a + 2);
177: $a = strlen($s);
178:
179: } else {
180: $arg = substr($statement, $a - 1, 1) === '$' || in_array(substr($statement, $a - 2, 2), array('->', '::'), TRUE)
181: ? self::formatMember($arg) : self::_dump($arg);
182: $statement = substr_replace($statement, $arg, $a, 1);
183: $a += strlen($arg);
184: }
185: $a = strpos($statement, '?', $a);
186: }
187: return $statement;
188: }
189:
190:
191: 192: 193: 194:
195: public static function formatMember($name)
196: {
197: return $name instanceof PhpLiteral || !self::isIdentifier($name)
198: ? '{' . self::_dump($name) . '}'
199: : $name;
200: }
201:
202:
203: 204: 205:
206: public static function isIdentifier($value)
207: {
208: return is_string($value) && preg_match('#^' . self::PHP_IDENT . '\z#', $value);
209: }
210:
211:
212:
213: public static function createObject($class, array $props)
214: {
215: return unserialize('O' . substr(serialize((string) $class), 1, -1) . substr(serialize($props), 1));
216: }
217:
218:
219: 220: 221: 222:
223: public static function ($name)
224: {
225: return ($pos = strrpos($name, '\\')) ? substr($name, 0, $pos) : '';
226: }
227:
228:
229: 230: 231: 232:
233: public static function ($name)
234: {
235: return ($pos = strrpos($name, '\\')) === FALSE ? $name : substr($name, $pos + 1);
236: }
237:
238: }
239: