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