动态类实例:好的实践?

发布于 2024-12-21 18:06:31 字数 594 浏览 2 评论 0原文

想象一下您有一些对象的列表。这些对象是扩展基类的各种类的实例。 现在我想将这些对象保存在数据库中。

作为附加要求,扩展基类的类的数量可能相当大。

将类名保存为数据库中的字符串并像这样获取它是一个好习惯吗:

<?php
class Page {
    abstract public function foo($args);
}

class ChartPage : Page{
    public function foo($args){
        var_dump($args);
    }
}

// other classes like ChartPage would be defined here

// fetched row from a MySQL database
$row = array("id" => 21, "title" => "Test", "class" => "ChartPage", "args" => "{}");
$object = new $row['class'];
$object->foo($row['args']);
?>

是否有任何做法可以以更好的方式做类似的事情?

Imagine you have a list of some objects. These objects are instances of various classes which are extending a base class.
Now I'd like to save these objects in a database.

As an additional requirement, the number of classes which extends the base class can be quite big.

Is it good practice to save the class name as string in the database and fetch it like that:

<?php
class Page {
    abstract public function foo($args);
}

class ChartPage : Page{
    public function foo($args){
        var_dump($args);
    }
}

// other classes like ChartPage would be defined here

// fetched row from a MySQL database
$row = array("id" => 21, "title" => "Test", "class" => "ChartPage", "args" => "{}");
$object = new $row['class'];
$object->foo($row['args']);
?>

Are there any practices to do anything like that in a better way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浪菊怪哟 2024-12-28 18:06:31

除非您有特定原因要编写自己的序列化/反序列化函数,否则请使用 PHP 中原生提供的函数:

您可以通过以下链接阅读有关 PHP 对象序列化的更多信息:

如果要与 PHP 之外的事物共享序列化数据,您可以选择其他序列化方法,例如 JSON 或 XML。但如果只是存储对象以便稍后通过 PHP 访问,那么标准序列化方法就足够了。


某种类型的标识符必须与序列化数据一起存储,否则您将无法确定对象的真正类型。

当然,我见过反序列化方法,其中序列化数据的键用于搜索最佳匹配的对象类型,但这不是我推荐的方法,因为它并不是在所有情况下都 100% 准确。


在您的示例片段中,我假设 Page::foo 将用作构建新类的工厂。

如果您要编写自己的序列化/反序列化数据的方法,并希望存储对象拥有的所有数据,则无需强制继承 Page 的类实现工厂。

Page 也可以有一个统一的方法,通过循环对象包含的键/值对来序列化任意类。但这种方法有一个小问题。

如果继承的对象有一个相当复杂的成员(即不是基本的,例如用户定义的类),您可能不想完全存储它。

例如,如果一个对象具有活动的 mysql 连接,您只想存储重新打开此类连接的凭据,因为您将如何将连接本身存储在序列化数据中?

话又说回来,存储与套接字连接关联的文件描述符并使用始终在后台运行的虚构的 MySQLKeepConnAlive 对象保持其打开状态会很酷,但这通常是不必要的。

无论如何;如果我是你,我会在基础对象中编写一个可用的序列化/反序列化的默认方法,如果继承的类型很复杂,则由开发人员覆盖这些方法并提供自己的方法。

我将使用如下的数据结构来存储对象,这与您之前描述的并没有那么远。 '__PAYLOAD' 将包含对象的成员,其他值应在您的基类中定义。

对于不同类的两个实例,“__PAYLOAD”看起来不会相同,但是将有一个统一的方法来加载具有特定 id 和类型的对象,并查找有关该对象的基本信息。

当然,您可以添加比下面更多的“基本”字段,这只是我的想法的一个例子。

$serialized_data = array (
  '__TITLE':    'Test',
  '__TYPE': 'CharPage',
  '__ID':           21,
  '__PAYLOAD': array (
    'member_1' => 'foobar',
    'member_2' => 'barbaz',
    'member_3' => 'bazbir'
  ) 
);

Unless you have a specific reason for writing your own functions for serialization/deserialization use those available natively in PHP:

You can read more about PHP's Object Serialization under the following link:

If the serialized data is to be shared with things outside of PHP you might choose another method of serialization, like JSON or XML. But if it's just a matter of storing objects for access later through PHP the standard serialization methods are more than sufficient.


Some sort of identifier must be stored with the serialized data, otherwise it will be impossible for you to determine what type an object really is.

Sure, I've seen deserialization methods where the keys of the serialized data has been used to search for the best matching object types, but this is not something I'd recommend since it isn't 100% accurate for all cases.


In your example snippet I assume that Page::foo is to be used as a factory building your new class.

If you are going to write your own methods of serializing/deserializing the data and want to store all the data an object has you don't need to force the classes who inherit Page to implement a factory.

Page could just as well have a unified method of serializing arbitrary classes by looping through the key/value-pairs that the object contains. There is a slight problem with this approach though.

If a inherited object has a rather complex member (ie. not basic, for example a user-defined class) you might not want to store exactly that.

For example, if an object has an active mysql connection you'll only want to store the credentials to reopen such a connection, because how are you going to store the connection itself in your serialized data?

Then again, storing the file descriptor associated with the socket connection and keeping it open using a imaginary MySQLKeepConnAlive object that's always running in the background would be cool, but it's often far som necessary.

Anyhow; If I was you I'd write a default method for serialization/deserialization available in the base object, if the inherited type is complex it's up to the developer to override these methods and provide his own methods.

I would store the object using a data structure as the below, which isn't that far from what you described earlier. '__PAYLOAD' will contain the members of the object, the other values should be defined in your base class.

'__PAYLOAD' will not look the same for two instances of different classes, but there will be an unified way of loading a object with a certain id and type, and finding out basic information regarding the object.

Of course you can add more "base" fields than the below, it's just an example of what I'm thinking.

$serialized_data = array (
  '__TITLE':    'Test',
  '__TYPE': 'CharPage',
  '__ID':           21,
  '__PAYLOAD': array (
    'member_1' => 'foobar',
    'member_2' => 'barbaz',
    'member_3' => 'bazbir'
  ) 
);
饭团 2024-12-28 18:06:31

尝试查看对象序列化。我认为这可能对您有帮助

http://php.net/manual/en/language .oop5.序列化.php

Try to look at object serialization. I think this might help you

http://php.net/manual/en/language.oop5.serialization.php

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文