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