代码之家  ›  专栏  ›  技术社区  ›  Marleen

PHP OOP:如何构造一个需要另一个映射程序提供功能的映射程序

  •  0
  • Marleen  · 技术社区  · 8 年前

    假设我有两个对象,类别和产品:

    类别

    <?php class Category {
        private $name;
    
        public function __construct(string $name) {
            $this->name = $name;
        }
    }
    ?>
    

    产品

    <?php class Product {
        private $name, $category;
    
        public function __construct(string $name, Category $category) {
            $this->name = $name;
            $this->category = $category;
        }
    }
    ?>
    

    我有一个CategoryMapper,它从数据库中获取(和插入/更新/删除)Category对象:

    分类管理员

    <?php
    class CategoryMapper {
        private $pdo;
    
        public function __construct(PDO $pdo) {
            $this->pdo = $pdo;
        }
    
        public function ofId($id) : ?Category {
    
            $query = 'SELECT name FROM category WHERE id = ?';
            $stmt = $pdo->prepare($query);
            $stmt->execute([$id]);
    
            if ($row = $stmt->fetch()) {
                return new Category($row['name']);
            }
    
            return null;
    
        }
    
        // Other methods
    }
    ?>
    

    我还需要一个ProductMapper,但是ProductMapper的 ofId() 方法需要返回一个包含Category对象的产品对象。

    现在我的问题是:我的ProductMapper应该如何构造?

    选项1-在构造函数中传递ProductMapper一个CategoryMapper

    如果CategoryMapper需要另一个Mapper,而Mapper又需要另一个Mapper,等等,我想这可能会变得很大。

    <?php
    class ProductMapper {
        private $pdo, $categoryMapper;
    
        public function __construct(PDO $pdo, CategoryMapper $categoryMapper) {
            $this->pdo = $pdo;
            $this->categoryMapper = $categoryMapper;
        }
    
        public function ofId($id) {
    
            $query = 'SELECT name, categoryId FROM product WHERE id = ?';
            $stmt = $pdo->prepare($query);
            $stmt->execute([$id]);
    
            if ($row = $stmt->fetch()) {
                $category = $this->categoryMapper->ofId($row['categoryId']);
                return new Product($row['name'], $category);
            }
    
            return null;
    
        }
    }
    ?>
    

    选项2-让ProductMapper在需要的方法中创建CategoryMapper

    如果ProductMapper需要很多其他的映射器,我可能会在这里忽略ProductMapper实际使用的映射器,因为它们不是在一个地方列出的,而是分散在整个代码中。

    <?php
    class ProductMapper {
        private $pdo;
    
        public function __construct(PDO $pdo) {
            $this->pdo = $pdo;
        }
    
        public function ofId($id) {
    
            $query = 'SELECT name, categoryId FROM product WHERE id = ?';
            $stmt = $pdo->prepare($query);
            $stmt->execute([$id]);
    
            if ($row = $stmt->fetch()) {
                $categoryMapper = new CategoryMapper($this->pdo);
                $category = $categoryMapper->ofId($row['categoryId']);
                return new Product($row['name'], $category);
            }
    
            return null;
    
        }
    }
    ?>
    

    选项3-不要使用CategoryMapper并在ProductMapper中复制build-a-category代码

    这只会导致大量重复的代码(特别是当嵌入的对象变大或对象也嵌入其中时)。

    <?php
    class ProductMapper {
        private $pdo;
    
        public function __construct(PDO $pdo) {
            $this->pdo = $pdo;
        }
    
        public function ofId($id) {
    
            $query = 'SELECT p.name as productName, c.name as categoryName FROM product p join category c on p.categoryId = c.id WHERE p.id = ?';
            $stmt = $pdo->prepare($query);
            $stmt->execute([$id]);
    
            if ($row = $stmt->fetch()) {
                $category = new Category($row['categoryName']);
                return new Product($row['productName'], $category);
            }
    
            return null;
    
        }
    }
    ?>
    

    那么这通常是怎么做的呢? 还有其他我没想到的选择吗?

    2 回复  |  直到 8 年前
        1
  •  1
  •   Damian Stępień    8 年前

    简而言之:第一种方法是正确的。您应该将所有依赖项作为参数传递到构造函数中。

    长话短说:第一个方法是正确的,但是使用一些依赖注入容器是一个很好的实践。它将负责初始化对象并将它们作为参数传递给其他对象。它还将确保每个类中只有一个对象被初始化。如果你想要轻便的,你可以 Pimple 或者,如果您更喜欢具有许多功能的可配置的产品, Symfony's DependencyInjection component .

        2
  •  0
  •   Nagesh    8 年前

    我认为应该在CategoryMapper类中添加一个singleton方法,如下所示

    public static $instance = null;    
    public static function getInstance() {
         if (self::$instance == null) {
            self::$instance = new self();
         }
    
         return self::$instance;
    }
    

    对ProductMapper的调用如下

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
        $this->categoryMapper = CategoryMapper::getInstance();
    }
    
    推荐文章