Switch statement decreases adaptability of a function
I fixed it by myself by introducing abstract classes, see below:
class Product {
    private int $id;
    private string $name;
    private int $price;
    private Category $category;
    
    public function __construct(int $id, string $name, int $price, Category $category) {
        $this-&gt;id = $id;
        $this-&gt;name = $name;
        $this-&gt;price = $price;
        $this-&gt;category = $category;
    }
    public function getId(): int
    {
        return $this-&gt;id;
    }
    public function getName(): string
    {
        return $this-&gt;name;
    }
    public function getPrice(): int
    {
        return $this-&gt;price;
    }
    public function getCategory(): Category
    {
        return $this-&gt;category;
    }
}

here it goes
abstract class Category { 
    abstract public function calculateTax(int $price): float;
}
class CategoryFurniture extends Category {
    public function calculateTax(int $price): float {
        return (float)($price / 100 * 21);
    }
}
class CategoryFood extends Category {
    public function calculateTax(int $price): float {
        return (float)($price / 100 * 9);
    }
}

//$product = new Product(200, 'Bread', 200, new CategoryFood); 
$product = new Product(100, 'Chair', 5000, new CategoryFurniture);

$taxForChair = calculateTax($product);
var_dump($taxForChair); // float 1050
exit;

function calculateTax(Product $product): float {
    
    $price = $product-&gt;getPrice();
    
    $category = $product-&gt;getCategory();
    return $category-&gt;calculateTax($price);
}