value = $value; $this->unit = $unit; } private function canOperate(AbstractUnit $with, bool $throw = false): bool { if ($with instanceof $this || $with instanceof CustomUnit) return true; if ($this instanceof CustomUnit && $with instanceof AbstractUnit) return true; if ($throw) throw new \InvalidArgumentException(sprintf( "Invalid type <%s>, expected of type \"%s\" or \"%s\"", get_class($with), get_class($this), CustomUnit::class )); return false; } protected function transformClass(CustomUnit $cu): self { return unserialize(preg_replace( '/^O:\d+:"[^"]++"/', sprintf('O:%d:"%s"', strlen(static::class), static::class), serialize($cu) )); } /** * Addition method * * @param AbstractUnit $with Unit to add with * @thows \InvalidArgumentException * */ public function add(AbstractUnit $with): self { $this->canOperate($with, true); return $this->transformClass( new CustomUnit($this->getValue() + $with->getValue(), $with->getUnit()) ); } /** * Multiplication method * * @param AbstractUnit $with Unit to multiply with * @thows \InvalidArgumentException * */ public function mul(AbstractUnit $with): self { $this->canOperate($with, true); return $this->transformClass( new CustomUnit($this->getValue() * $with->getValue(), $with->getUnit()) ); } /** * Divide method * * @param AbstractUnit $with Unit to divide with * @thows \InvalidArgumentException * */ public function div(AbstractUnit $with): self { $this->canOperate($with, true); return $this->transformClass( new CustomUnit($this->getValue() / $with->getValue(), $with->getUnit()) ); } /** * Get the value * * @return float */ public function getValue(): float { return $this->value; } /** * Return the unit (e.g «degree») * * @return string */ public function getUnit(): string { return $this->unit; } /** * {@inheritDoc} */ public function diff(DiffInterface $d): int { if ($d instanceof $this) return $this->value - $d->getValue(); return 0; } public function __toString(): string { return sprintf( "%s: %f %s", basename(str_replace( '\\', DIRECTORY_SEPARATOR, get_class($this) )), $this->value, $this->unit); } }