/** * Determines the type for the given type name, which is used, e.g., for return specifications. * * @param string $name the name * @return PC_Obj_MultiType the type */ public function get_type_by_name($name) { switch ($name) { case 'array': return PC_Obj_MultiType::create_array(); case 'callable': return PC_Obj_MultiType::create_callable(); case 'bool': return PC_Obj_MultiType::create_bool(); case 'float': return PC_Obj_MultiType::create_float(); case 'int': return PC_Obj_MultiType::create_int(); case 'string': return PC_Obj_MultiType::create_string(); case 'self': // TODO get class name return PC_Obj_MultiType::create_object(); default: return PC_Obj_MultiType::create_object($name); } }
/** * Handles the instanceof-operator * * @param PC_Obj_MultiType $e the expression * @param PC_Obj_MultiType $name the name of the class * @return PC_Obj_MultiType the result */ public function handle_instanceof($e, $name) { if (!$e instanceof PC_Obj_MultiType) { return $this->handle_error('$e is invalid'); } $cname = $name->get_string(); // if we're in a loop or the name is not a string, give up if ($this->vars->is_in_loop() || $cname === null) { return PC_Obj_MultiType::create_bool(); } // if we don't know the type or its class we can't say wether its a superclass $classname = $e->get_classname(); if ($classname === null) { return PC_Obj_MultiType::create_bool(); } // class-name equal? if (strcasecmp($classname, $cname) == 0) { return PC_Obj_MultiType::create_bool(true); } // if the class is unknown we can't say more $class = $this->env->get_types()->get_class($classname); if ($class === null) { return PC_Obj_MultiType::create_bool(); } // check super-classes $super = $class->get_super_class(); while ($super != '') { if (strcasecmp($super, $cname) == 0) { return PC_Obj_MultiType::create_bool(true); } $superobj = $this->env->get_types()->get_class($super); if ($superobj === null) { break; } $super = $superobj->get_super_class(); } // check interfaces if ($this->is_instof_interface($class->get_interfaces(), $cname)) { return PC_Obj_MultiType::create_bool(true); } return PC_Obj_MultiType::create_bool(false); }
public function test__isset() { // public bool __isset ( string $name ) $code = '<?php class A { public function __isset($name); } class B { /** * @return int */ public function __isset($name); } ?>'; list(, $classes, , , $errors) = $this->analyze($code); $params = array(new PC_Obj_Parameter('name', PC_Obj_MultiType::create_string())); $m = $classes['a']->get_method('__isset'); self::assertParamsEqual($params, $m->get_params()); self::assert_equals((string) PC_Obj_MultiType::create_bool(), (string) $m->get_return_type()); $m = $classes['b']->get_method('__isset'); self::assertParamsEqual($params, $m->get_params()); self::assert_equals(3, count($errors)); $error = $errors[0]; self::assert_equals(PC_Obj_Error::E_S_RET_SPEC_BUT_NO_RET, $error->get_type()); self::assert_regex('/The function\\/method "#A#::__isset" has a return-specification in PHPDoc, but does not return a value/', $error->get_msg()); $error = $errors[1]; self::assert_equals(PC_Obj_Error::E_T_MAGIC_METHOD_RET_INVALID, $error->get_type()); self::assert_regex('/The return-type of the magic-method "#B#::__isset" is invalid \\(expected="bool", found="integer"\\)/', $error->get_msg()); $error = $errors[2]; self::assert_equals(PC_Obj_Error::E_S_RET_SPEC_BUT_NO_RET, $error->get_type()); self::assert_regex('/The function\\/method "#B#::__isset" has a return-specification in PHPDoc, but does not return a value/', $error->get_msg()); }
function yy_r473() { $this->_retvalue = PC_Obj_MultiType::create_bool(); }
public function test_special() { $code = '<?php $u = `foo`; // we can even say the type/value of variable variables if we can figure out the variable name ^^ $v = "u"; $w = ${$v}; $x = ${"unknown var"}; $y = ${123}; // array-union works when all values are known $z = array("a" => 1,"c" => 123,"d" => 5) + array("a" => 2,"b" => 4); $aa = array(array($_,1)) + array(2); // comparison is just bool $ab = array(1) === array(1); $ac = array(1,"2") == array(1,2); $ad = array(1) <> array($_); $ba = 1 ? 0 : 2; $bb = 4 ? "bla" : "blub"; $bc = $_ ? 1 : 2; $bd = $_ ? "foo" : 1; $be = (1) ? ((2) ? "a" : "b") : "c"; $bf = 1 ?: -1; $bg = "f" ?: "g"; ?>'; list(, , $vars, , $errors) = $this->analyze($code); self::assert_equals(0, count($errors)); $global = $vars[PC_Obj_Variable::SCOPE_GLOBAL]; self::assert_equals((string) PC_Obj_MultiType::create_string(), (string) $global['u']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_string(), (string) $global['w']->get_type()); self::assert_equals((string) new PC_Obj_MultiType(), (string) $global['x']->get_type()); self::assert_equals((string) new PC_Obj_MultiType(), (string) $global['y']->get_type()); self::assert_equals((string) PC_Obj_Type::get_type_by_value(array("a" => 1, "c" => 123, "d" => 5, "b" => 4)), (string) $global['z']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $global['aa']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_bool(), (string) $global['ab']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_bool(), (string) $global['ac']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_bool(), (string) $global['ad']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_int(0), (string) $global['ba']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_string("bla"), (string) $global['bb']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_int(), (string) $global['bc']->get_type()); self::assert_equals((string) new PC_Obj_MultiType(array(new PC_Obj_Type(PC_Obj_Type::STRING, "foo"), new PC_Obj_Type(PC_Obj_Type::INT, 1))), (string) $global['bd']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_string("a"), (string) $global['be']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_int(1), (string) $global['bf']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_int(-1), (string) $global['bg']->get_type()); }
/** * Checks if the given method is "magic". If so it adds automatically parameter-types (if not * already set). * * @param string $classname the class-name * @param PC_Obj_Method $method the method * @return bool true if handled */ private function handle_magic($classname, $method) { // the magic-methods: // public void __set ( string $name , mixed $value ) // public mixed __get ( string $name ) // public bool __isset ( string $name ) // public void __unset ( string $name ) // public mixed __call ( string $name , array $arguments ) // public mixed __callStatic ( string $name , array $arguments ) // * array __sleep( void ) // * void__wakeup( void ) // public string __toString( void ) // public void __invoke( ... ) // public static object __set_state( array $props ) // * void __clone( void ) $ismagic = true; $visibility = PC_Obj_Visible::V_PUBLIC; $static = false; $expected = null; switch (strtolower($method->get_name())) { case '__set': $expected = array(new PC_Obj_Parameter('name', PC_Obj_MultiType::create_string()), new PC_Obj_Parameter('value', new PC_Obj_MultiType())); break; case '__isset': case '__unset': case '__get': $expected = array(new PC_Obj_Parameter('name', PC_Obj_MultiType::create_string())); break; case '__call': case '__callstatic': $expected = array(new PC_Obj_Parameter('name', PC_Obj_MultiType::create_string()), new PC_Obj_Parameter('arguments', PC_Obj_MultiType::create_array())); break; case '__tostring': $expected = array(); break; case '__sleep': case '__wakeup': case '__clone': $visibility = null; // may be private or protected $expected = array(); break; case '__invoke': $static = true; break; case '__set_state': $expected = array(new PC_Obj_Parameter('props', PC_Obj_MultiType::create_array())); break; default: $ismagic = false; break; } if (!$ismagic) { return false; } if ($visibility !== null && $method->get_visibility() != $visibility) { $this->report($method, 'The magic method "#' . $classname . '#::' . $method->get_name() . '" should be public', PC_Obj_Error::E_T_MAGIC_NOT_PUBLIC); } if ($static && !$method->is_static()) { $this->report($method, 'The magic method "#' . $classname . '#::' . $method->get_name() . '" should be static', PC_Obj_Error::E_T_MAGIC_NOT_STATIC); } else { if (!$static && $method->is_static()) { $this->report($method, 'The magic method "#' . $classname . '#::' . $method->get_name() . '" should not be static', PC_Obj_Error::E_T_MAGIC_IS_STATIC); } } if ($expected !== null) { $changed = false; if ($this->check_params($classname, $method, $expected, $method->get_params())) { // set parameter-descriptions $i = 0; foreach ($method->get_params() as $param) { $param->set_mtype($expected[$i++]->get_mtype()); $param->set_has_doc(true); $changed = true; } } $return = new PC_Obj_MultiType(); switch (strtolower($method->get_name())) { case '__set': case '__unset': case '__wakeup': case '__clone': $return = PC_Obj_MultiType::create_void(); break; case '__set_state': $return = PC_Obj_MultiType::create_object(); break; case '__isset': $return = PC_Obj_MultiType::create_bool(); break; case '__sleep': $return = PC_Obj_MultiType::create_array(); break; case '__tostring': $return = PC_Obj_MultiType::create_string(); break; } if ($method->has_return_doc() && !$this->env->get_types()->is_type_conforming($method->get_return_type(), $return)) { // its ok to specify a more specific return-value if the expected one is "mixed" if (!$return->is_unknown()) { $this->report($method, 'The return-type of the magic-method "#' . $classname . '#::' . $method->get_name() . '" is invalid ' . '(expected="' . $return . '", found="' . $method->get_return_type() . '")', PC_Obj_Error::E_T_MAGIC_METHOD_RET_INVALID); } } if ($return !== null && !$method->has_return_doc()) { $method->set_return_type($return); $method->set_has_return_doc(true); $changed = true; } if ($changed) { $this->env->get_storage()->update_function($method, $method->get_class()); } } return true; }
/** * Creates a multitype with type BOOL and given value * * @param string $file the file of the def * @param int $line the line of the def * @param bool $value the value * @param string $varname optionally, the variable-name * @return PC_Obj_Variable the variable */ public static function create_bool($file, $line, $value = null, $varname = '') { return new self($file, $line, $varname, PC_Obj_MultiType::create_bool($value)); }
public function test_vars() { $code = '<?php define("MYCONST",123); $i1 = +1; $i2 = -412; $i3 = MYCONST; $i4 = (int)"abc"; $f1 = 0.5; $f2 = 0.123; $f3 = 1.0; $f4 = (float)(string)2; $s1="my\'str"; $s2 = \'str2\'; $s3 = "ab $b c\'a\\\\\\""."bla"; $s4 = "ab c\'a\\\\\\""."bla"; $b1 = true; $b2 = false; $a1 = array(); $a2 = array(1); $a3 = ARRAY(1,2,3); $a4 = array(1 => 2,3 => 4,5 => 6); $a5 = array(\'a\' => 1,2,3,\'4\'); $a6 = array(array(array(1,2,3),4),5); $a7 = (array)1; $a8 = 4; unset($a8); $a9 = "foo"; $a10 = 123; unset($a9,$a10); /** * @param array $a * @param MyClass $b * @return int */ function x($a,MyClass $b) { global $b1; $i1 = $a; $i2 = $i1; return 1; } ?>'; $options = new PC_Engine_Options(); $options->add_project(PC_Project::PHPREF_ID); $options->add_min_req('PHP', '5'); list(, , $vars, , $errors) = $this->analyze($code, $options); self::assert_equals(0, count($errors)); $global = $vars[PC_Obj_Variable::SCOPE_GLOBAL]; self::assert_equals((string) PC_Obj_MultiType::create_int(1), (string) $global['i1']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_int(-412), (string) $global['i2']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_int(123), (string) $global['i3']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_int(0), (string) $global['i4']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_float(0.5), (string) $global['f1']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_float(0.123), (string) $global['f2']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_float(1.0), (string) $global['f3']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_float(2.0), (string) $global['f4']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_string('my\'str'), (string) $global['s1']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_string('str2'), (string) $global['s2']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_string(), (string) $global['s3']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_string('ab c\'a\\\\\\"bla'), (string) $global['s4']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_bool(true), (string) $global['b1']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_bool(false), (string) $global['b2']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_array(array()), (string) $global['a1']->get_type()); $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array(1))); self::assert_equals((string) $array, (string) $global['a2']->get_type()); $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array(1, 2, 3))); self::assert_equals((string) $array, (string) $global['a3']->get_type()); $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array(1 => 2, 3 => 4, 5 => 6))); self::assert_equals((string) $array, (string) $global['a4']->get_type()); $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array('a' => 1, 2, 3, '4'))); self::assert_equals((string) $array, (string) $global['a5']->get_type()); $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array(array(array(1, 2, 3), 4), 5))); self::assert_equals((string) $array, (string) $global['a6']->get_type()); $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value((array) 1)); self::assert_equals((string) $array, (string) $global['a7']->get_type()); self::assert_equals(false, isset($global['a8'])); self::assert_equals(false, isset($global['a9'])); self::assert_equals(false, isset($global['a10'])); $x = $vars['x']; self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $x['a']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_object('MyClass'), (string) $x['b']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $x['i1']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $x['i2']->get_type()); self::assert_equals((string) PC_Obj_MultiType::create_bool(true), (string) $x['b1']->get_type()); }