Пример #1
0
 public function __ToString()
 {
     $str = $this->visibility . ' ' . ($this->static ? 'static ' : '') . $this->get_name();
     if (!$this->type->is_unknown()) {
         $str .= '[' . $this->type . ']';
     }
     return $str;
 }
Пример #2
0
 /**
  * Determines the type from the operation (assumes that the type or the value is unknown)
  * 
  * @param string $op the operator
  * @param PC_Obj_MultiType $t1 the type of the first operand
  * @param PC_Obj_MultiType $t2 the type of the second operand (may be null for unary ops)
  * @return PC_Obj_MultiType the variable
  */
 protected function get_type_from_op($op, $t1, $t2 = null)
 {
     switch ($op) {
         // bitwise operators have always int as result
         case '|':
         case '&':
         case '^':
         case '>>':
         case '<<':
         case '~':
         case '?:':
             return PC_Obj_MultiType::create_int();
             // concatenation leads always to string
         // concatenation leads always to string
         case '.':
             return PC_Obj_MultiType::create_string();
         case '+':
         case '-':
         case '*':
         case '/':
         case '%':
             // if one of them is unknown we don't know whether we would get a float or int
             if ($t1->is_unknown() || $t1->is_multiple() || $t2 !== null && ($t2->is_unknown() || $t2->is_multiple())) {
                 return new PC_Obj_MultiType();
             }
             $ti1 = $t1->get_first()->get_type();
             $ti2 = $t2 === null ? -1 : $t2->get_first()->get_type();
             // if both are arrays, the result is an array
             if ($ti1 == PC_Obj_Type::TARRAY && $ti2 == PC_Obj_Type::TARRAY) {
                 return PC_Obj_MultiType::create_array();
             }
             // if one of them is float, the result is float
             if ($ti1 == PC_Obj_Type::FLOAT || $ti2 == PC_Obj_Type::FLOAT) {
                 return PC_Obj_MultiType::create_float();
             }
             // otherwise its always int
             return PC_Obj_MultiType::create_int();
         case '==':
         case '!=':
         case '===':
         case '!==':
         case '<':
         case '>':
         case '<=':
         case '>=':
         case '&&':
         case '||':
         case 'xor':
         case '!':
             // always bool
             return PC_Obj_MultiType::create_bool();
         default:
             FWS_Helper::error('Unknown operator "' . $op . '"');
     }
 }
Пример #3
0
 /**
  * Adds the given expression as thrown
  * 
  * @param PC_Obj_MultiType $expr the expression
  */
 public function add_throw($expr)
 {
     if (!$expr instanceof PC_Obj_MultiType) {
         $this->handle_error('$expr is invalid');
         return;
     }
     // don't even collect unknown types here
     if (!$expr->is_unknown()) {
         $this->throws_analyzer->add(PC_Obj_Method::THROW_SELF, $expr);
     }
 }
Пример #4
0
 /**
  * Checks whether $arg is ok for $param
  *
  * @param PC_Obj_Location $loc the location
  * @param PC_Obj_MultiType $arg the argument
  * @param PC_Obj_Parameter $param the parameter
  * @return boolean true if so
  */
 private function is_argument_ok($loc, $arg, $param)
 {
     // not present but required?
     if ($arg === null && !$param->is_optional() && !$param->is_first_vararg()) {
         return false;
     }
     // unknown / not present
     if ($arg === null) {
         return true;
     }
     // callables are special
     if ($param->get_mtype()->get_first()->get_type() == PC_Obj_Type::TCALLABLE) {
         if (!$arg->is_unknown()) {
             $this->check_callable($loc, $arg);
             return true;
         }
     }
     // arg in the allowed types?
     return $this->env->get_types()->is_type_conforming($arg, $param->get_mtype());
 }
Пример #5
0
 /**
  * Checks whether $types contains a type, that is not contained in $mtype.
  * 
  * @param array $types the types
  * @param PC_Obj_MultiType $mtype the multitype
  * @return bool true if so
  */
 private function has_forbidden($types, $mtype)
 {
     // if the type is unknown (mixed), its always ok
     if ($mtype->is_unknown()) {
         return false;
     }
     foreach ($types as $t) {
         if ($t !== null && !$this->env->get_types()->is_type_conforming($t, $mtype)) {
             return true;
         }
     }
     return false;
 }
Пример #6
0
 /**
  * Checks whether $actual is okay for $spec.
  *
  * @param PC_Obj_MultiType $actual the actual type
  * @param PC_Obj_MultiType $spec the specified type, i.e., the one to check against
  * @return bool true if ok
  */
 public function is_type_conforming($actual, $spec)
 {
     if ($actual->is_unknown() || $spec->is_unknown()) {
         return true;
     }
     // every actual type has to be contained in at least one of the specified types
     $count = 0;
     foreach ($actual->get_types() as $atype) {
         $ok = false;
         foreach ($spec->get_types() as $stype) {
             if ($atype->equals($stype)) {
                 $ok = true;
                 break;
             }
             // floats can accept ints
             if ($atype->get_type() == PC_Obj_Type::INT && $stype->get_type() == PC_Obj_Type::FLOAT) {
                 $ok = true;
                 break;
             }
             // if both are objects, check if the actual is the same or a subclass of the spec
             $objs = $atype->get_type() == PC_Obj_Type::OBJECT && $stype->get_type() == PC_Obj_Type::OBJECT;
             if ($objs && ($stype->get_class() == '' || (strcasecmp($atype->get_class(), $stype->get_class()) || $this->is_subclass_of($atype->get_class(), $stype->get_class())))) {
                 $ok = true;
                 break;
             }
         }
         // early exit?
         if (!$ok && $this->options->get_report_argret_strictly()) {
             return false;
         }
         if ($ok && !$this->options->get_report_argret_strictly()) {
             return true;
         }
         if ($ok) {
             $count++;
         }
     }
     return $count > 0;
 }
Пример #7
0
 /**
  * Returns a variable pointing to the array-element with given key. If it does not exist, it
  * will be created as soon as the type is assigned.
  *
  * @param PC_Obj_MultiType $key the key (null = append)
  * @return PC_Obj_Variable the type of the element
  */
 public function array_offset($key)
 {
     assert(!$this->type->is_multiple() && !$this->type->is_unknown());
     $first = $this->type->get_first();
     assert($first->get_type() == PC_Obj_Type::TARRAY);
     // fetch element or create it
     $akey = $key;
     if ($key === null) {
         $akey = $key = $first->get_next_array_key();
     } else {
         if (!$key->is_unknown()) {
             $akey = $key;
             $key = $first->get_array_type($key->get_first()->get_value());
         }
     }
     $var = new self($this->get_file(), $this->get_line(), '', $key);
     // connect the var to us
     $var->arrayref = $this;
     $var->arrayoff = $akey;
     return $var;
 }
Пример #8
0
 /**
  * Merges all types in the given multitype into this one. Clones the types in it.
  * 
  * @param PC_Obj_MultiType $mtype the type to merge with
  * @param bool $set_unknown whether to set the types to unknown when $this or $mtype is unknown
  */
 public function merge($mtype, $set_unknown = true)
 {
     // if one is unknown, the merged type is unknown as well
     if ($set_unknown && ($this->is_unknown() || $mtype->is_unknown())) {
         $this->types = array();
         return;
     }
     if (!isset($mtype->types)) {
         return;
     }
     foreach ($mtype->types as $type) {
         $found = false;
         foreach ($this->types as $ttype) {
             if ($ttype->equals($type)) {
                 $found = true;
                 break;
             }
         }
         // if we already have this type, check if the values are different
         if ($found) {
             // if so simply unset the value, because we don't know it anymore
             if ($ttype->get_value() !== $type->get_value()) {
                 $ttype->set_value(null);
             }
         } else {
             $this->types[] = clone $type;
         }
     }
 }