You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP OOP中如何让属性仅接受指定格式的关联数组

确保MarketStall类$products属性的类型约束

原有代码

Product类

class Product
{
    private $name;
    private $price;
    private $sellingByKg;


    public function __construct($name = null, $price = null, $sellingByKg = null)
    {
        $this->name = $name;
        $this->price = $price;
        $this->sellingByKg = $sellingByKg;
    }

    public function getName()
    {
        return $this->name;
    }
    public function getPrice()
    {
        return $this->price;
    }
    public function getSellingByKg()
    {
        return $this->sellingByKg;
    }
}

原有MarketStall类

class MarketStall extends Product
{
    public $products;

    public function __construct(
        $products= [],
        $name = null,
        $price = null,
        $sellingByKg = null
    ) {
        parent::__construct($name, $price, $products);
        $this->products = $products;
    }
}

需求

确保MarketStall类的$products属性仅接受关联数组,该数组的键为产品名称(字符串类型),值为Product类的实例对象。

修改后的MarketStall类

class MarketStall extends Product
{
    // 改为私有属性,避免外部直接赋值绕过验证
    private array $products = [];

    public function __construct(
        array $products = [],
        $name = null,
        $price = null,
        $sellingByKg = null
    ) {
        // 修正父类构造函数的参数错误:原代码将$products误传给了$sellingByKg参数
        parent::__construct($name, $price, $sellingByKg);
        // 验证并设置products
        $this->setProducts($products);
    }

    /**
     * 设置products数组,验证每个键值对是否符合要求
     * @param array $products
     * @throws InvalidArgumentException
     */
    public function setProducts(array $products): void
    {
        $validatedProducts = [];
        foreach ($products as $productName => $product) {
            // 验证键是否为字符串类型(产品名称)
            if (!is_string($productName)) {
                throw new InvalidArgumentException('产品数组的键必须是字符串类型的产品名称');
            }
            // 验证值是否为Product实例
            if (!$product instanceof Product) {
                throw new InvalidArgumentException(sprintf('产品"%s"必须是Product类的实例', $productName));
            }
            // 可选:确保产品实例的名称和数组键一致,避免数据不一致
            if ($product->getName() !== $productName) {
                throw new InvalidArgumentException(sprintf('产品数组键"%s"与产品实例名称"%s"不匹配', $productName, $product->getName()));
            }
            $validatedProducts[$productName] = $product;
        }
        $this->products = $validatedProducts;
    }

    /**
     * 获取products数组
     * @return array
     */
    public function getProducts(): array
    {
        return $this->products;
    }

    // 可选:添加单个产品的添加方法
    public function addProduct(Product $product): void
    {
        $productName = $product->getName();
        if ($productName === null) {
            throw new InvalidArgumentException('产品必须设置名称才能添加到MarketStall');
        }
        $this->products[$productName] = $product;
    }
}

关键修改说明

  • 属性私有化:将$products改为私有属性,强制通过setProducts或addProduct方法修改,避免外部直接赋值跳过验证逻辑。
  • 构造函数修正:修复了原代码中调用父类构造函数时的参数错误,解决$products误传的问题。
  • 严格验证逻辑:
    • 遍历传入数组,检查每个键是否为字符串类型,确保是产品名称
    • 检查每个值是否为Product类的实例
    • 可选验证:确保数组键与产品实例的name属性一致,避免数据不一致
  • 类型声明:对构造函数参数和方法参数添加array类型声明,明确参数类型。

内容的提问来源于stack exchange,提问作者Raitiko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 15:10:44