Esempio n. 1
0
 /**
  * Adds a function-call
  * 
  * @param PC_Obj_MultiType $class the class-name (or null)
  * @param PC_Obj_MultiType $func the function-name
  * @param array $args the function-arguments
  * @param bool $static whether its a static call
  * @return PC_Obj_MultiType the result
  */
 public function add_call($class, $func, $args, $static = false)
 {
     if ($class !== null && !$class instanceof PC_Obj_MultiType) {
         return $this->handle_error('$class is invalid');
     }
     if (!$func instanceof PC_Obj_MultiType) {
         return $this->handle_error('$func is invalid');
     }
     if (!is_array($args)) {
         return $this->handle_error('$args is invalid');
     }
     // if we don't know the function- or class-name, we can't do anything here
     $cname = $class !== null ? $class->get_string() : null;
     $fname = $func->get_string();
     if ($fname === null || $class !== null && $cname === null) {
         return $this->create_unknown();
     }
     // create call
     $call = new PC_Obj_Call($this->get_file(), $this->get_line());
     // determine class- and function-name
     $call->set_function($fname);
     // do it manually here because we might not know the method
     $call->set_object_creation(strcasecmp($fname, '__construct') == 0 || strcasecmp($fname, $cname) == 0);
     if ($class !== null) {
         // support for php4 constructors
         if (strcasecmp($cname, $fname) == 0) {
             $call->set_object_creation(true);
         } else {
             if (strcasecmp($cname, 'parent') == 0) {
                 // in this case its no object-creation for us because it would lead to reports like
                 // instantiation of abstract classes when calling the constructor of an abstract
                 // parent-class
                 $call->set_object_creation(false);
                 $cname = $this->scope->get_name_of(T_CLASS_C);
                 $classobj = $this->env->get_types()->get_class($cname);
                 if ($classobj === null || $classobj->get_super_class() == '') {
                     return $this->create_unknown();
                 }
                 $cname = $classobj->get_super_class();
                 // if we're in a static method, the call is always static
                 $curfname = $this->scope->get_name_of(T_FUNC_C);
                 $curfunc = $classobj->get_method($curfname);
                 if ($curfunc === null || $curfunc->is_static()) {
                     $static = true;
                 } else {
                     // if we're in a non-static method, its a static-call if the method we're calling is
                     // static, and not if its not. i.e. we basically don't detect errors here
                     $func = null;
                     $super = $this->env->get_types()->get_class($cname);
                     if ($super !== null) {
                         $func = $super->get_method($fname);
                     }
                     $static = $func !== null && $func->is_static();
                 }
             } else {
                 if (strcasecmp($cname, 'self') == 0) {
                     $cname = $this->scope->get_name_of(T_CLASS_C);
                     // self is static if its not a constructor-call
                     $static = !$call->is_object_creation();
                 }
             }
         }
         $call->set_class($cname);
     }
     // clone because it might be a variable
     foreach ($args as $arg) {
         if (!$arg instanceof PC_Obj_MultiType) {
             $this->handle_error('$arg is invalid');
             continue;
         }
         $call->add_argument(clone $arg);
     }
     $call->set_static($static);
     $this->env->get_types()->add_call($call);
     $funcobj = $this->env->get_types()->get_method_or_func($cname, $fname);
     $this->calls_analyzer->analyze($call);
     $this->modifiers_analyzer->analyze($this->scope, $call, $funcobj);
     if ($funcobj === null) {
         // if it's a constructor, we still know the type
         if ($call->is_object_creation()) {
             return PC_Obj_MultiType::create_object($cname);
         }
         return $this->create_unknown();
     }
     // reference parameters implicitly create variables
     $i = 0;
     foreach ($funcobj->get_params() as $param) {
         if ($i >= count($args)) {
             break;
         }
         // this is a hack: we store the variable name for missing variable names when the variable
         // appears. when detecting calls, we check whether there are reference parameters and then
         // use the name to implicitly create the variable
         if ($param->is_reference() && $args[$i]->get_missing_varname() !== null) {
             $var = new PC_Obj_Variable($this->get_file(), $this->get_line(), $args[$i]->get_missing_varname(), clone $param->get_mtype());
             $this->vars->set($this->scope->get_name(), $var);
             $args[$i]->set_missing_varname(null);
         }
         $i++;
     }
     $this->req_analyzer->analyze($call, $funcobj->get_version()->get_min(), $funcobj->get_version()->get_max());
     // add the throws of the method to our throws
     foreach (array_keys($funcobj->get_throws()) as $tclass) {
         $this->throws_analyzer->add(PC_Obj_Method::THROW_FUNC, PC_Obj_MultiType::create_object($tclass));
     }
     // if its a constructor we know the type directly
     if ($call->is_object_creation()) {
         return PC_Obj_MultiType::create_object($cname);
     }
     return clone $funcobj->get_return_type();
 }
Esempio n. 2
0
 /**
  * Builds an instance of PC_Obj_Call from the given row
  *
  * @param array $row the row from the db
  * @return PC_Obj_Call the call
  * @throws Exception if the arguments can't be serialized
  */
 private function build_call($row)
 {
     $c = new PC_Obj_Call($row['file'], $row['line']);
     $c->set_id($row['id']);
     $c->set_class($row['class']);
     $c->set_function($row['function']);
     $c->set_static($row['static']);
     $c->set_object_creation($row['objcreation']);
     $args = $row['arguments'] ? unserialize($row['arguments']) : array();
     if ($args === false) {
         throw new Exception("Unable to unserialize '" . $row['arguments'] . "'");
     }
     foreach ($args as $arg) {
         $c->add_argument($arg);
     }
     return $c;
 }