/** * Creates a parameter with given attributes. * * @param string $name the name * @param PC_Obj_MultiType $type the type from type hinting (or null) * @param PC_Obj_MultiType $val the default value (or null) * @param bool $optional whether it's optional * @param bool $ref whether it's a reference * @return PC_Obj_Parameter the parameter */ public function create_parameter($name, $type, $val, $optional, $ref) { $p = new PC_Obj_Parameter($name); if ($val) { $val->clear_values(); } // value is not interesting here if ($type && !$type->is_unknown()) { $p->set_mtype($type); } else { if ($val) { $p->set_mtype($val); $p->set_mtype_default(true); } } $p->set_optional($optional); $p->set_reference($ref); return $p; }
/** * 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()); }
/** * Sets the given function-parameter for the current scope * * @param PC_Obj_Parameter $p the parameter */ public function set_func_param($p) { if (!$p instanceof PC_Obj_Parameter) { $this->handle_error('$p is invalid'); return; } $var = $this->get_var(PC_Obj_MultiType::create_string($p->get_name())); // give type-hinting the highest prio, because I think its the most trustable type if (!$p->get_mtype()->is_unknown()) { $this->set_var($var, $p->get_mtype()); return; } // if a variable-type is unknown and we're in a function/class, check if we know the type // from the type-scanner $func = $this->env->get_types()->get_method_or_func($this->scope->get_name_of(T_CLASS_C), $this->scope->get_name_of(T_FUNC_C)); // if we have a doc, use it. otherwise use the default-value $doc = $this->get_funcparam_type($func, $p->get_name()); if ($doc !== null) { $this->set_var($var, $doc); } else { $this->set_var($var, $p->get_mtype()); } }
/** * Parses a method-description into a PC_Obj_Method * * @param string $file the filename * @param string $desc the description * @return array an array of the class-name and the PC_Obj_Method * @throws PC_PHPRef_Exception if it failed */ public static function parse_method_desc($file, $desc) { $classname = ''; // find link to method if (preg_match('/<a href="(.*?)" class="methodname">/', $desc, $m)) { $file = dirname($file) . '/' . $m[1]; } // prepare description $desc = trim(strip_tags($desc)); $desc = FWS_StringHelper::htmlspecialchars_back($desc); // filter out modifier, return-type, name and params $match = array(); $res = preg_match('/^(?:(abstract|static|final|public|protected|private)\\s*)?' . '(?:(abstract|static|final|public|protected|private)\\s*)?' . '(?:(abstract|static|final|public|protected|private)\\s*)?' . '(?:(\\S+)\\s+)?' . '([a-zA-Z0-9_:\\-\\>]+)\\s*\\((.*?)\\)$/s', $desc, $match); if (!$res) { throw new PC_PHPRef_Exception('Unable to parse "' . $desc . '"'); } list(, $modifier1, $modifier2, $modifier3, $return, $name, $params) = $match; // detect class-names if (($pos = strpos($name, '::')) !== false || ($pos = strpos($name, '->')) !== false) { $classname = substr($name, 0, $pos); $name = substr($name, $pos + 2); } // build basic method $method = new PC_Obj_Method($file, 0, $classname != ''); if ($modifier1 == 'static' || $modifier2 == 'static' || $modifier3 == 'static') { $method->set_static(true); } if ($modifier1 == 'final' || $modifier2 == 'final' || $modifier3 == 'final') { $method->set_final(true); } if ($modifier1 == 'abstract' || $modifier2 == 'abstract' || $modifier3 == 'abstract') { $method->set_abstract(true); } if (in_array($modifier1, array('private', 'protected'))) { $method->set_visibility($modifier1); } else { if (in_array($modifier2, array('private', 'protected'))) { $method->set_visibility($modifier2); } else { if (in_array($modifier3, array('private', 'protected'))) { $method->set_visibility($modifier3); } } } if ($return) { $method->set_return_type(PC_Obj_MultiType::get_type_by_name($return)); // set this always for builtin types since it makes no sense to report errors for // inherited classes or similar $method->set_has_return_doc(true); } $method->set_name($name); // check what kind of params we have $optional = ''; $firstopt = strpos($params, '['); if ($firstopt !== false) { $required = substr($params, 0, $firstopt); $optional = substr($params, $firstopt + 1); $optional = str_replace(array('[', ']'), '', $optional); } else { $required = $params; } // add required ones $required = trim($required); if ($required && $required != 'void') { $reqparts = explode(', ', $required); foreach ($reqparts as $part) { list($type, $name) = explode(' ', trim($part)); $param = new PC_Obj_Parameter(); $param->set_name(trim($name)); $param->set_mtype(self::get_param_type($type)); $param->set_has_doc(true); $method->put_param($param); } } // add optional ones $optional = trim($optional); if ($optional) { $optparts = explode(', ', $optional); foreach ($optparts as $part) { $part = trim($part); if ($part == '') { continue; } $default = null; $param = new PC_Obj_Parameter(); $param->set_optional(true); // has it a known default-value? if (($pos = strpos($part, '=')) !== false) { $nametype = trim(substr($part, 0, $pos)); $default = trim(substr($part, $pos + 1)); $parts = preg_split('/\\s+/', $nametype); if (count($parts) != 2) { throw new PC_PHPRef_Exception('Parameter description has not 2 parts: "' . $nametype . '"'); } list($type, $name) = $parts; } else { // detect variable arguments if (strpos($part, '...') !== false) { $param->set_first_vararg(true); // sometimes there is a space bewteen $ and ... $part = preg_replace('/\\$\\s+\\.\\.\\./', '$...', $part); } $parts = preg_split('/\\s+/', $part); if (count($parts) != 2) { throw new PC_PHPRef_Exception('Parameter description has not 2 parts: "' . $part . '"'); } list($type, $name) = $parts; } // detect references if (substr($name, 0, 1) == '&') { $param->set_reference(true); $name = substr($name, 1); } $param->set_name(trim($name)); $param->set_mtype(self::get_param_type($type, $default)); $param->set_has_doc(true); $method->put_param($param); } } return array('func', $classname, $method); }