/** * @param XRef_ParsedFile $pf * @param bool $is_library_file * @return * any data */ public function createFileSlice(XRef_IParsedFile $pf, $is_library_file = false) { /** array of arrays with info about called functions and methods */ $called_functions = array(); /** map: (function call info => true), to report any call once only */ $uniqs = array(); /** map of function names, checked for existence by function_exists() */ $checked_for_functions = array(); $tokens = $pf->getTokens(); for ($i = 0; $i < count($tokens); ++$i) { $t = $tokens[$i]; // $this->foo(); // Foo\Barr::foo(); if ($t->text == '(') { $p = $t->prevNS(); if ($p->kind != T_STRING) { continue; } // array with parts of the name (T_NS_SEPARATOR && T_STRING) $function_name_parts = array($p->text); $class_name = ''; $pp = $p->prevNS(); if ($pp->kind == T_NS_SEPARATOR) { // Foo\bar(); // \bar(); while ($pp->kind == T_NS_SEPARATOR || $pp->kind == T_STRING) { array_unshift($function_name_parts, $pp->text); $pp = $pp->prevNS(); } } elseif ($pp->kind == T_OBJECT_OPERATOR) { // $var->bar() // $this->bar(); $pp = $pp->prevNS(); if ($pp->kind == T_VARIABLE && $pp->text == '$this') { $class_name = 'self'; // will be resolved later } else { // TODO continue; } } elseif ($pp->kind == T_DOUBLE_COLON) { // Foo::bar(); // Foo\Bar::bar(); // self::foo(); // static::bar(); $pp = $pp->prevNS(); while ($pp->kind == T_NS_SEPARATOR || $pp->kind == T_STRING || $pp->kind == T_STATIC) { $class_name = $pp->text . $class_name; $pp = $pp->prevNS(); } } if ($pp->text == '&') { $pp = $pp->prevNS(); } if ($pp->kind == T_FUNCTION) { // skip function declarations continue; } $arguments = $pf->extractList($t->nextNS()); $num_of_arguments = count($arguments); $from_class = $pf->getClassAt($t->index); $from_class_name = $from_class ? $from_class->name : ''; if ($pp->kind == T_NEW) { // new Something(); // new ns\Another\Something(); // new \Foo(); $class_name = implode('', $function_name_parts); if ($class_name == 'static' || $class_name == 'self') { $class_name = $from_class_name; } elseif ($class_name == 'parent') { $class_name = $from_class && $from_class->extends ? $from_class->extends[0] : null; } else { $class_name = $pf->qualifyName($class_name, $t->index); } if ($class_name) { $uniq = "new##{$class_name}#{$num_of_arguments}"; if (!isset($uniqs[$uniq])) { $uniqs[$uniq] = true; $called_functions[] = array(self::F_CLASS_CONSTRUCTOR, null, $class_name, $t->lineNumber, $num_of_arguments); } } } elseif ($class_name) { // method call: // $this->foo(); // self::foo(); // Foo::bar(); // \bar\Baz::foo(); if ($class_name == 'static' || $class_name == 'self') { $class_name = $from_class_name; } elseif ($class_name == 'parent') { $class_name = $from_class && $from_class->extends ? $from_class->extends[0] : null; } else { $class_name = $pf->qualifyName($class_name, $t->index); } if ($class_name) { if (count($function_name_parts) > 1) { throw new Exception("{$class_name}::" . implode('', $function_name_parts)); } $function_name = $function_name_parts[0]; if ($function_name == '__construct') { $uniq = "new##{$class_name}#{$num_of_arguments}"; if (!isset($uniqs[$uniq])) { $uniqs[$uniq] = true; $called_functions[] = array(self::F_CLASS_CONSTRUCTOR, null, $class_name, $t->lineNumber, $num_of_arguments); } } else { $uniq = "{$function_name}##{$class_name}#{$num_of_arguments}"; if (!isset($uniqs[$uniq])) { $uniqs[$uniq] = true; $called_functions[] = array(self::F_CLASS_METHOD, $function_name, $class_name, $t->lineNumber, $num_of_arguments); } } } } else { // function call: qualified or unqualified // foo(); // foo\bar(); // \foo\bar\baz(); if (count($function_name_parts) > 1) { $function_name = $pf->qualifyName(implode('', $function_name_parts), $t->index); $uniq = "{$function_name}##{$num_of_arguments}"; if (!isset($uniqs[$uniq])) { $uniqs[$uniq] = true; $called_functions[] = array(self::F_FULLY_QUALIFIED_FUNC, $function_name, null, $t->lineNumber, $num_of_arguments); } } else { $function_name = $function_name_parts[0]; $namespace = $pf->getNamespaceAt($t->index); $namespace_name = $namespace ? $namespace->name : ''; $uniq = "{$function_name}##{$namespace_name}#{$num_of_arguments}"; if (!isset($uniqs[$uniq])) { $uniqs[$uniq] = true; $called_functions[] = array(self::F_NOT_QUALIFIED_FUNC, $function_name, $namespace_name, $t->lineNumber, $num_of_arguments, $from_class_name); } } if ($function_name == 'function_exists') { $n = $t->nextNS(); if ($n->kind == T_CONSTANT_ENCAPSED_STRING) { $checked_for_function_name = trim($n->text, '\'"'); $checked_for_functions[$checked_for_function_name] = true; } } } } } $file_slice = array("called" => $called_functions, "checked" => $checked_for_functions); return $file_slice; }