/** * Parses PHP file. * @param string * @return array [class => [prop => comment (or 'use' => [alias => class])] */ public static function parsePhp($code) { if (XApp_Utils_Strings::match($code, '#//nette' . 'loader=(\\S*)#')) { return; // TODO: allways ignore? } $tokens = @token_get_all($code); $namespace = $class = $classLevel = $level = $docComment = NULL; $res = $uses = array(); while (list($key, $token) = each($tokens)) { switch (is_array($token) ? $token[0] : $token) { case T_DOC_COMMENT: $docComment = $token[1]; break; case T_NAMESPACE: $namespace = self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)) . '\\'; $uses = array(); break; case T_CLASS: case T_INTERFACE: case PHP_VERSION_ID < 50400 ? -1 : T_TRAIT: if ($name = self::fetch($tokens, T_STRING)) { $class = $namespace . $name; $classLevel = $level + 1; if ($docComment) { $res[$class]['class'] = $docComment; } if ($uses) { $res[$class]['use'] = $uses; } } break; case T_FUNCTION: self::fetch($tokens, '&'); if ($level === $classLevel && $docComment && ($name = self::fetch($tokens, T_STRING))) { $res[$class][$name] = $docComment; } break; case T_VAR: case T_PUBLIC: case T_PROTECTED: self::fetch($tokens, T_STATIC); if ($level === $classLevel && $docComment && ($name = self::fetch($tokens, T_VARIABLE))) { $res[$class][$name] = $docComment; } break; case T_USE: while (!$class && ($name = self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)))) { if (self::fetch($tokens, T_AS)) { $uses[self::fetch($tokens, T_STRING)] = ltrim($name, '\\'); } else { $tmp = explode('\\', $name); $uses[end($tmp)] = $name; } if (!self::fetch($tokens, ',')) { break; } } break; case T_CURLY_OPEN: case T_DOLLAR_OPEN_CURLY_BRACES: case '{': $level++; break; case '}': if ($level === $classLevel) { $class = $classLevel = NULL; } $level--; // break omitted // break omitted case ';': $docComment = NULL; } } return $res; }