Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP:OOP设计和如何跨类似类重用方法_Php_Oop_Interface_Abstract Class - Fatal编程技术网

PHP:OOP设计和如何跨类似类重用方法

PHP:OOP设计和如何跨类似类重用方法,php,oop,interface,abstract-class,Php,Oop,Interface,Abstract Class,我熟悉扩展父类,但是我不知道如何创建一个从父类继承工作方法的类,这个类可能会根据它所在的类而变化。例如,对于存储日志元数据的数据库表,我有一个名为Log_Metadata的模型类。我还有一个名为Station_Metadata的类,用于存储站点元数据的表。除了站点或日志ID的控制字段外,表模式类似,但模式的其余部分相同,因为每个元数据行都有一个ID、一个meta_键列和一个meta_值列 我基本上想为这些模型创建一个通用方法,它允许我在各种模型之间添加/编辑/删除元数据。在这种情况下,使用抽象类

我熟悉扩展父类,但是我不知道如何创建一个从父类继承工作方法的类,这个类可能会根据它所在的类而变化。例如,对于存储日志元数据的数据库表,我有一个名为Log_Metadata的模型类。我还有一个名为Station_Metadata的类,用于存储站点元数据的表。除了站点或日志ID的控制字段外,表模式类似,但模式的其余部分相同,因为每个元数据行都有一个ID、一个meta_键列和一个meta_值列


我基本上想为这些模型创建一个通用方法,它允许我在各种模型之间添加/编辑/删除元数据。在这种情况下,使用抽象类或接口是否合适?如果模型端发生变化,如何覆盖该方法?

首先考虑这应该是您的初始设置

  • 元数据(接口,定义元数据的基本内容,在任何共享条件下)
  • MetadataAbstract(实现元数据、接口并提供所有元数据共享的基本方法)
  • 元数据\日志(添加属性和特定于日志的方法)
  • 元数据\站点(添加属性和…)

此外,您可能需要考虑将表结构更改为更类似于

的内容。
  • 元数据(共享列)
    • 元数据日志(特定于日志)
    • 元数据_站点(特定于站点)
其中两个特定表都与元数据表(1-1)有关系。然后,您可以查询元数据日志/元数据站点表,并加入主元数据表中的结果

正如其他人所建议的那样,实现Doctrine2这样令人敬畏的东西将通过鉴别器映射解决这个问题。但是,它可能超出您的应用程序的范围

我希望这能给你更多的启示:-)

编辑1 _这是在快速巡演中做的。。。如果我遗漏了什么,我想这就是你的意思。前提是除了命名之外,您的细节没有“具体”的实现

<?php
namespace Example;

    interface Metadata {
        function getKey();
        function getValue();
    }

    abstract class AbstractMetadata implements Metadata {
        abstract protected function getKey()
        {
            return 5;
        }

        protected function getValue()
        {
            return 3;
        }
    }

    // use Example\AbstractMetadata;

    class LogMetadata extends AbstractMetadata {
        public function getKey()
        {
            return 1;
        }

        public function getValue()
        {
            return 2;
        }
    }

    // use Example\AbstractMetadata;

    class StationMetadata extends AbstractMetadata {
        public function getKey()
        {
            return 2;
        }

        public function getValue()
        {
            return parent::getValue(); // 3
        }
    }

我不确定你是否应该这样设计。听起来您应该从保存数据的类中抽象出常用方法(也许您想使用
DataMapper
?)。但是如果你认为这种继承的
ActiveRecord
模式是有意义的,我想你是想做这样的事情吗

abstract class Base
{
    public function add($data)
    {
        $something = do_stuff($this->getId($data));
    }

    abstract protected function getId($data);
}

class Derived extends Base
{
    private $idKey = 'DerivedKey';

    protected function getId($data)
    {
        return $data[$this->idKey];
    }
}

在您的例子中,您将使用通用方法(CRUD),但调用抽象保护方法来获取特定的内容

这是
模板方法模式

编辑:如果您认为可能有添加额外列/元数据等的类,那么可以尝试另一种方法

abstract class Base
{
    public function add($data)
    {
        $something = array();
        $something[] = do_stuff($this->getId($data));
        $something[] = do_stuff($this->getName($data));
        $something[] = $this->additionalFields($data);
    }

    abstract protected function getId($data);
    abstract protected function getName($data);

    protected function additionalFields($data)
    {
        // no additional fields by default
    }
}

class Derived extends Base
{
    private $idKey = 'DerivedKey';
    private $nameKey = 'DerivedName';
    private $other = 'new thing';

    protected function getId($data)
    {
        return $data[$this->idKey];
    }

    protected function getName($data)
    {
        return $data[$this->nameKey];
    }

    protected function additionalFields($data)
    {
        return do_foo($this->other, $data);
    } 
}
请记住,这些都是向您展示OOP模式的精心设计的示例。例如,我假设
getId
可能更复杂。如果您的产品一直遵循这种模式,那么更好的设计可能是:

class Base
{
    protected $metadata = array(
        'id' => 'defaultId',
        'name' => 'defaultName'
    );

    public function add($data)
    {
        foreach ($metadata as $key => $value) {
            do_something($key, $data[$value]);
        }
    }
}

class Derived extends Base
{
    public function __construct()
    {
        $this->metadata['id'] = 'DIfferentId';
    }
}

同样,这只是一种可以根据需要进行调整的模式。

您真的确定表结构永远不会改变吗?有很多用于持久性的库[例如,条令],您可能想看看它们。肯定的。如果需要,我只提供一个关系表。我只需要ID、meta_键、meta_值和关系映射器ID。@moonwave99谢谢你的建议,但我没有这个选项。Hmmmm。好的,这很有帮助。所以元数据提供了必需的方法,MetadataAbstract允许在后一个类中重写使用?我想我想在这里要做的是,如果元数据对象有特殊的处理情况,则重写CRUD功能的默认方法。我试试这个。Thank=)没有元数据将只是定义元数据是什么/有什么的接口。我会用一个例子更新我的帖子…谢谢@Matt的反馈非常好!这个例子真的帮了大忙。干杯很高兴我能帮忙!祝你的项目好运:-)!我将很快发布一个TMDB(电影数据库)的API包装,您可能有兴趣看看。如果需要,我可以覆盖抽象类add()?当然,为什么不呢?但是你得到了什么?你没有针对特定片段的通用方法吗?您应该编写
add
,这样将要定制的任何内容都可以在另一个
受保护的
方法中处理。请注意,如果想提供默认实现,则不需要对上面的代码<>代码> GETId <代码>进行抽象。请把上面的评论考虑到@ CuFrFik,它询问元数据结构是否会发生变化,我说它不会,如果有数据的附件,我会把它指向相关表,因此,我需要对该关系数据进行操作(从而在重写方法中处理该数据)。现在,虽然情况并非如此,所以这一点无关紧要,但它可能会在某个时候出现。不过我理解getId()的概念,我根本不需要重写它。
class Base
{
    protected $metadata = array(
        'id' => 'defaultId',
        'name' => 'defaultName'
    );

    public function add($data)
    {
        foreach ($metadata as $key => $value) {
            do_something($key, $data[$value]);
        }
    }
}

class Derived extends Base
{
    public function __construct()
    {
        $this->metadata['id'] = 'DIfferentId';
    }
}