/** * Checks whether the method with given name may be a method of a subclass of $class * * @param PC_Obj_Class $class the class * @param string $name the method-name * @return bool true if so */ private function is_method_of_sub($class, $name) { if ($class->is_final()) { return false; } $cname = $class->get_name(); $isif = $class->is_interface(); foreach ($this->env->get_types()->get_classes() as $sub) { if ($sub && (!$isif && strcasecmp($sub->get_super_class(), $cname) == 0 || $isif && $sub->is_implementing($cname))) { if ($sub->contains_method($name)) { return true; } if ($this->is_method_of_sub($sub, $name)) { return true; } } } return false; }
/** * Adds the member from <var>$class</var> to <var>$data</var>. That means, inheritance is * performed. * * @param PC_Obj_Class $data the class to which the members should be added * @param string $class the class-name * @param boolean $overwrite just internal: whether the members should be overwritten */ private function add_members($data, $class, $overwrite = true) { $cobj = $this->env->get_types()->get_class($class); if ($cobj !== null) { if (strcasecmp($class, $data->get_name()) != 0) { // methods foreach ($cobj->get_methods() as $function) { if ($function->get_visibility() != PC_Obj_Visible::V_PRIVATE) { // if we don't want to overwrite the methods and the method is already there // we add just the types that are not known yet if (!$overwrite && ($f = $data->get_method($function->get_name())) !== null) { $changed = false; /* @var $f PC_Obj_Method */ if (!$f->has_return_doc()) { $f->set_return_type($function->get_return_type()); $f->set_has_return_doc($function->has_return_doc()); $changed = true; } // add missing throws foreach (array_keys($function->get_throws()) as $tclass) { if (!$f->contains_throw($tclass)) { $f->add_throw($tclass, PC_Obj_Method::THROW_PARENT); $changed = true; } } foreach ($function->get_params() as $param) { $fparam = $f->get_param($param->get_name()); // just replace the parameter if it exists and the type is unknown yet if ($fparam !== null && $fparam->get_mtype()->is_unknown()) { $f->put_param($param); $changed = true; } } if ($changed) { $this->env->get_storage()->update_function($f, $data->get_id()); } } else { $clone = clone $function; // change constructor-name, if it is an old-style-one if (strcasecmp($function->get_name(), $cobj->get_name()) == 0) { $clone->set_name($data->get_name()); } $clone->set_id($this->env->get_storage()->create_function($clone, $data->get_id())); $data->add_method($clone); } } } // fields foreach ($cobj->get_fields() as $field) { if ($field->get_visibility() != PC_Obj_Visible::V_PRIVATE) { $clone = clone $field; $data->add_field($clone); $this->env->get_storage()->create_field($clone, $data->get_id()); } } // constants foreach ($cobj->get_constants() as $const) { $clone = clone $const; $data->add_constant($clone); $this->env->get_storage()->create_constant($clone, $data->get_id()); } } // protect ourself from recursion here. in fact, Iterator implements itself, so that this is // actually necessary. if (strcasecmp($class, $cobj->get_super_class()) != 0) { $this->add_members($data, $cobj->get_super_class(), false); } foreach ($cobj->get_interfaces() as $interface) { if (strcasecmp($class, $interface) != 0) { $this->add_members($data, $interface, false); } } } }
/** * Puts constants, fields and methods from the given statements into $class * * @param PC_Obj_Class $class the class * @param array $stmts an array of PC_Obj_Constant, PC_Obj_Field and PC_Obj_Method */ private function handle_class_stmts($class, $stmts) { foreach ($stmts as $stmt) { if ($stmt instanceof PC_Obj_Constant) { $class->add_constant($stmt); } else { if ($stmt instanceof PC_Obj_Field) { $class->add_field($stmt); } else { if ($stmt instanceof PC_Obj_Method) { // methods in interfaces are implicitly abstract if ($class->is_interface()) { $stmt->set_abstract(true); } // convert old-style constructors to the new ones if (strcasecmp($stmt->get_name(), $class->get_name()) == 0) { $stmt->set_name('__construct'); } // constructors return an object of the class if ($stmt->is_constructor() && ($stmt->get_return_type() && !$stmt->get_return_type()->is_unknown())) { $spec = $stmt->get_return_type(); $this->report_error('The constructor of class ' . $class->get_name() . ' specifies return type ' . $spec, PC_Obj_Error::E_T_RETURN_DIFFERS_FROM_DOC, $stmt->get_line()); } $class->add_method($stmt); } else { FWS_Helper::error('Unknown statement: ' . $stmt); } } } } }
/** * @see FWS_Module::run() */ public function run() { $tpl = FWS_Props::get()->tpl(); if (!$this->class) { $this->report_error(); return; } $curl = PC_URL::get_mod_url(); $classname = $this->class->get_name(); // build class-declaration $declaration = ''; if (!$this->class->is_interface()) { if ($this->class->is_abstract()) { $declaration .= 'abstract '; } else { if ($this->class->is_final()) { $declaration .= 'final '; } } $declaration .= 'class '; } else { $declaration .= 'interface '; } $declaration .= $classname . ' '; if (!$this->class->is_interface() && ($cn = $this->class->get_super_class())) { $declaration .= 'extends <a href="' . $curl->set('name', $cn)->to_url() . '">' . $cn . '</a> '; } if (count($this->class->get_interfaces()) > 0) { $declaration .= !$this->class->is_interface() ? 'implements ' : 'extends '; foreach ($this->class->get_interfaces() as $if) { $declaration .= '<a href="' . $curl->set('name', $if)->to_url() . '">' . $if . '</a>, '; } $declaration = FWS_String::substr($declaration, 0, -1); } $declaration = FWS_String::substr($declaration, 0, -1) . ';'; $tpl->add_variables(array('classname' => $classname, 'declaration' => $declaration)); $classfile = $this->class->get_file(); // constants $consts = array(); foreach ($this->class->get_constants() as $const) { $consts[] = array('name' => $const->get_name(), 'type' => $const->get_type(), 'line' => $const->get_line(), 'url' => $this->get_url($classfile, $const)); } $tpl->add_variable_ref('consts', $consts); // fields $fields = array(); $cfields = $this->class->get_fields(); ksort($cfields); foreach ($cfields as $field) { $fields[] = array('name' => $field->get_name(), 'type' => (string) $field, 'line' => $field->get_line(), 'url' => $this->get_url($classfile, $field)); } $tpl->add_variable_ref('fields', $fields); // methods $methods = array(); $cmethods = $this->class->get_methods(); ksort($cmethods); foreach ($cmethods as $method) { $methods[] = array('name' => $method->get_name(), 'type' => $method->__ToString(), 'line' => $method->get_line(), 'url' => $this->get_url($classfile, $method), 'since' => implode(', ', $method->get_version()->get_min()), 'till' => implode(', ', $method->get_version()->get_max())); } $tpl->add_variable_ref('methods', $methods); if ($this->class->get_file() && $this->class->get_line()) { $source = PC_Utils::highlight_file($this->class->get_file()); } else { $source = ''; } $tpl->add_variables(array('source' => $source, 'file' => $this->class->get_file(), 'line' => $this->class->get_line(), 'since' => implode(', ', $this->class->get_version()->get_min()), 'till' => implode(', ', $this->class->get_version()->get_max()))); }