/** * 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; }