如何在不随机创建对象的情况下在抽象类中调用方法?

How to call method inside abstract class without randomly creating an object?

提问人:Giorgi Chagelishvili 提问时间:10/19/2023 更新时间:10/19/2023 访问量:53

问:

我正在用PHP编码,试图构建CRUD应用程序。

我有 DVD书籍家具类,它们扩展了抽象的产品类。

要求是主要的产品逻辑(创建、读取、删除等)必须在 Product 类中实现,其他类(即产品类型)应扩展主 Product 类。

我在 Product 类中有 getAllProducts() 方法,它从数据库中获取所有产品,但是我从 ProductManager 类调用此方法,我创建该类纯粹是为了在 Product 类中调用 getAllProducts() 和 deleteProducts() 方法,它没有其他函数。

我也很乐意收到有关代码结构的反馈/提示。

产品类别:

<?php

abstract class Product extends Dbh
{
    public string $sku;
    public string $name;
    public float $price;
    public string $attribute;
    public string $attribute_value;
    public string $attribute_unit;
    public string $type;

    public function __construct(string $sku = '', string $name = '', float $price = 0, string $attribute = '', string $attribute_value = '', string $attribute_unit = '', string $type = '')
    {
        $this->sku = $sku;
        $this->name = $name;
        $this->price = $price;
        $this->attribute = $attribute;
        $this->attribute_value = $attribute_value;
        $this->attribute_unit = $attribute_unit;
        $this->type = $type;
    }

    public function deleteProducts(array $skuArray)
    {
        $conn = $this->connect();

        try {
            $placeholders = rtrim(str_repeat('?, ', count($skuArray)), ', ');

            $sql = "DELETE FROM products WHERE product_sku IN ($placeholders)";
            $stmt = $conn->prepare($sql);
            $stmt->execute($skuArray);

            $conn = null;
            return true;
        } catch (PDOException $e) {
            $conn = null;
            return false;
        }
    }

    // Select and fetch every product from the database
    public function getAllProducts()
    {
        $conn = $this->connect();

        $sql = "SELECT * FROM products;";
        $stmt = $conn->prepare($sql);

        if (!$stmt->execute()) {
            $stmt = null;
            $conn = null;
            exit();
        }

        $products = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $conn = null;
        return $products;
    }

    // Save product to the database
    public function saveProduct()
    {
        $sku = htmlspecialchars(strip_tags($this->getSku()));
        $name = htmlspecialchars(strip_tags($this->getName()));
        $price = htmlspecialchars(strip_tags($this->getPrice()));
        $formattedPrice = number_format($price, 2);
        $attribute = htmlspecialchars(strip_tags($this->getAttribute()));
        $attribute_value = htmlspecialchars(strip_tags($this->getAttributeValue()));
        $attribute_unit = htmlspecialchars(strip_tags($this->getAttributeUnit()));

        $conn = $this->connect();

        $sql = "INSERT INTO products(product_sku, product_name, product_price, product_attribute, attribute_value, attribute_unit) VALUES (?, ?, ?, ?, ?, ?);";
        $stmt = $conn->prepare($sql);

        if (!$stmt->execute([$sku, $name, $formattedPrice, $attribute, $attribute_value, $attribute_unit])) {
            $stmt = null;
            $conn = null;
            exit();
        }

        $conn = null;
    }

    // Retrieve attribute input details from the database
    public function getAttributeInputs()
    {
        $conn = $this->connect();

        $sql = "SELECT * FROM attribute_inputs WHERE product_type = ?;";
        $stmt = $conn->prepare($sql);

        if (!$stmt->execute([$this->getType()])) {
            $stmt = null;
            $conn = null;
            exit();
        }

        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $conn = null;
        return $result;
    }

    // GETTERS ~ GETTERS ~ GETTERS ~ GETTERS ~ GETTERS ~ GETTERS ~ GETTERS ~ GETTERS ~ GETTERS ~ GETTERS
    public function getSku()
    {
        return $this->sku;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getPrice()
    {
        return $this->price;
    }

    public function getAttribute()
    {
        return $this->attribute;
    }

    public function getAttributeValue()
    {
        return $this->attribute_value;
    }

    public function getAttributeUnit()
    {
        return $this->attribute_unit;
    }

    public function getType()
    {
        return $this->type;
    }

    // SETTERS ~ SETTERS ~ SETTERS ~ SETTERS ~ SETTERS ~ SETTERS ~ SETTERS ~ SETTERS ~ SETTERS ~ SETTERS

    public function setSku($sku)
    {
        $this->sku = $sku;
    }

    public function setName($name)
    {
        $this->name = $name;
    }

    public function setPrice($price)
    {
        $this->price = $price;
    }

    public function setAttribute($attribute)
    {
        $this->attribute = $attribute;
    }

    public function setAttributeValue($attribute_value)
    {
        $this->attribute_value = $attribute_value;
    }

    public function setAttributeUnit($attribute_unit)
    {
        $this->attribute_unit = $attribute_unit;
    }
}


DVD 类:

<?php

class DVD extends Product
{
    public int $size;

    public string $attribute = 'Size';
    public string $attribute_unit = 'MB';
    public string $type = 'DVD';

    public function __construct(string $sku = '', string $name = '', float $price = 0, array $attribute_values = [])
    {
        $this->setSize($attribute_values);
        parent::__construct($sku, $name, $price, $this->attribute, $this->getSize(), $this->attribute_unit, $this->type);
    }

    public function getSize()
    {
        return $this->size;
    }

    public function setSize(array $attribute_values)
    {
        if (!empty($attribute_values)) {
            $this->size = $attribute_values[0];
        } else {
            $this->size = 0;
        }
    }
}

ProductManager 类:

<?php

class ProductManager extends Product
{
    public function fetchAllProducts()
    {
        $products = $this->getAllProducts();
        return $products;
    }

    public function callDeleteProducts(array $skuArray)
    {
        $response = $this->deleteProducts($skuArray);

        if ($response === true) {
            return true;
        }
    }
}

我尝试在 ProductManager 类中实现 get 和 delete 方法,但要求说所有产品逻辑都应该在 Products 类中实现,我不知道如何在抽象类中调用这些方法,而不会随机创建某个类的对象来扩展它。

我想过创建一个 DVD、Book 或 Furniture 对象并通过它们调用这些方法,但我认为创建 DVD 对象以删除 Furniture(例如)并不是最佳做法。

或者创建 Book 对象,以便从数据库中获取每种类型的产品......

php oop 多态性 抽象类

评论

1赞 shingo 10/19/2023
这是一个设计错误。Product 对象应包含从数据库查询返回的一行结果,而 ProductManager 是用于查询数据的类,您现在已经将它们混合在一起。这是您从某个教程中看到的练习吗?
1赞 Chris Haas 10/19/2023
与您的问题无关,而是复制和粘贴安全尝试的代码气味。您已经在使用准备好的语句,因此不需要在该方向上进行转义。也许没关系,但如果有人想写一本名为《This This》的书,那将打破这一点。通常,在输入时进行过滤/验证,在输出时进行转义。$sku = htmlspecialchars(strip_tags($this->getSku()))strip_tagsWhy I love <h1> tags
1赞 Chris Haas 10/19/2023
对于您遵循的模式,CRUD 通常是关于单个实例的,因此对象可能具有 或方法,但我不希望或成为其中的一部分。此外,所有产品逻辑都可以与 Product 一起存在,但这并不一定意味着/包括数据库逻辑。以对你有意义的方式构建它,并询问“要求”它的人。fetch()delete()fetchAll()deleteAll()
0赞 Giorgi Chagelishvili 10/19/2023
@shingo 是的,我在某些教程中看到过这种做法。我不太明白它应该如何工作,你能给我举个例子吗?
0赞 Giorgi Chagelishvili 10/19/2023
@ChrisHaas 感谢您的反馈,我将确保更正验证部分。这是公司的测试任务,不幸的是,我无法向他们询问代码结构或应该在哪里实现什么。你能告诉我在这种特殊情况下,什么做法更好吗?我应该在 ProductManager 类中实现 fetchAll() 方法吗?

答: 暂无答案