【问题标题】:Abstract Static Function in PHP 5.3PHP 5.3 中的抽象静态函数
【发布时间】:2012-05-24 14:55:55
【问题描述】:

我是 PHP 的新手,我正在寻找实现一些数据库访问代码的最佳方法。我正在尝试创建一些简单的数据库访问对象——每个表都有自己的类,该类的每个实例代表表中的一行,你知道的。

我的代码似乎可以工作,但我在网上看到的一些内容让我担心我的方法可能会以某种方式出错。自从“我可以这样做吗?” “我应该这样做吗?”是两个不同的问题,我希望一些 PHP 专家能加入进来。

我目前的策略是创建一个包含所有通用代码的基本抽象 Table 类,然后让代表单个表的每个类对其进行扩展。

我主要关心的是这段代码:


abstract class Table {
    protected abstract static function get_fields();
    protected abstract static function get_primary_key();
    protected abstract static function get_table_name();

想法是每个实现类都会定义字段名、主键、表名等,然后 Table 类将使用这些函数来填充特定的空白,如下所示:


    static function insert($values) {
        $field_list = array();
        $value_list = array();
        foreach (static::get_fields() as $field_name) {
            if (isset($values[$field_name])) {
                $field_list[] = $field_name;
                $value_list[] = self::escape($values[$field_name]);
            }
        }
        $field_string = join(", ", $field_list);
        $value_string = "'" . join("', '", $value_list) . "'";

        $sql = "insert into " . static::get_table_name() . " ($field_string) values ($value_string)";

如您所见,关键是我正在访问那些static abstract 函数,方法是在它们前面加上static::。据我所知,它正在工作!

但是,this question 接受的答案表明 abstract static 函数在 5.3 中仍然是不允许的。

所以,我想弄清楚该怎么做。答案是否错误——abstract static 函数现在被认为是完全合法的 PHP 代码吗?我在我的代码中做了一些不可取的事情吗?我应该考虑另一种方法吗?

【问题讨论】:

  • 如果你说“你知道交易”,我肯定知道一件事:交易就是不为此使用静态函数。如果您认为是这样,那一定是空检查器处理,因为静态函数不适用于您喜欢使用的继承。另外我建议您阅读 PoEEA,我的意思是,您知道交易类型的书,对吗?
  • @hakre:这种敌意和屈尊从何而来? “你知道演习”是对我认为不值得深究的一种相当标准的数据库内容建模方法的参考。
  • 请参考您所描述的是一种相当标准的方法。
  • 有许多可用于 PHP 的 ORM 框架,包括(但不限于)DoctrineZend FrameworkPropel。这是一个非常复杂的轮子;你确定要重新发明它吗?
  • @Phoenix:说真的?主啊,没有。但我的选择令人不快;我们没有适合生产服务器的系统管理员,并且那里的 PHP 安装......我会很好,称之为“功能轻”。安装任何有趣的东西对我来说都太白痴了。我宁愿自己造轮子,尽管它可能不完美,也不愿一直拖着雪橇。

标签: php design-patterns


【解决方案1】:

这是你的例子

abstract class Table implements iTable {

    public static function insert() {
        $class = get_called_class();
        $sql = 'INSERT INTO '.$class::get_class_name();
        echo $sql;
    }    

}

interface iTable {
    static function get_class_name();
}    


class ConcreteTable extends Table
{
    public function ConcreteTable() {}

    static function get_class_name() {
        return 'ConcreteTable';
    }

}

$t = new ConcreteTable();
$t::insert();

这个例子尊重对象范式,即使 PHP 停止支持后期静态绑定(我认为这是 PHP 的特殊性),你确信它会工作

编辑: 两个答案都表明,抽象类引入接口以及从它扩展的类是未知的。遵循模板模式,这在 PHP 中即使使用静态函数也是可能的(尽管有充分的理由给您提供严格的标准警告)。概念证明:

abstract class Table
{
    abstract static function get_class_name();
    public static function insert() {
        printf('INSERT INTO %s', static::get_class_name());
    }    

}

class ConcreteTable extends Table
{
    public static function get_class_name() {
        return 'ConcreteTable';
    }
}

ConcreteTable::insert();

如果你去掉这里的静态关键字,你实际上会得到有用的(和标准的做事方式)代码:

abstract class Table
{
    protected $table = NULL;
    public function insert() {
        printf('INSERT INTO %s', $this->table);
    }    

}

class ConcreteTable extends Table
{
    protected $table = 'ConcreteTable';
}

$table = new ConcreteTable();
...
$table->insert();

【讨论】:

  • 嗯,为什么那里有明显多余的new - 你只需要一个字符串,例如$t = 'ConcretTable'; 为什么不让它依赖于使用 __FUNCTION__ 常量读取的某些函数名称?或者更常见:将表名添加为受保护的属性(或 SQL 查询)?
  • 邀请一个界面加入聚会似乎给了我我正在寻找的行为,而没有任何逻辑悖论使我的代码混乱。你有我的谢意。 :-)
  • @hakre : new 只是 Java 习惯
  • get_call_class() 可以代替需要为类所代表的表命名。那么你可以有一个 getTableName() 来返回 get_call_class(),它可以被各个类覆盖以自定义表名
【解决方案2】:

在任何语言中,抽象函数都永远不会是静态的。

静态函数提供功能,即使没有实例。

抽象函数不提供任何功能。

从逻辑上讲,您不能使用抽象的静态函数,它会--总是并且永远-- 提供功能。


B 扩展 A

当您在 B 上下文中调用静态函数时,它将在 A 上下文中运行(由于静态状态)。

但是,在 A 上下文中,同样的函数是抽象的,你不能调用它。

【讨论】:

  • 所以,对于我是否在做一些不可取的事情的问题,这将是“是”。您是否对 PHP 似乎让我侥幸逃脱的原因有任何见解,或者对不那么自相矛盾的替代方法的建议?
  • 您使用的对象范式错误。我同意 abstract 关键字,但是这 3 个函数将始终在实例上工作,它们不应该是静态的。
  • 为什么它们不应该是静态的? User 对象的字段列表将在所有 User 对象中保持一致;它不依赖于实例。同样,我认为我应该能够在类而不是实例化对象上调用“插入”或“选择”。
  • 您的静态函数,如插入,只能在 B 类中运行。如果你永远不会调用它(而且永远不能),为什么要在 A 上下文中放置一个静态插入函数?
  • 因为该插入函数的代码在所有 B 类中基本上是相同的——所有的变化是表的名称和字段的名称。继承模型在这里对我来说非常有意义。你觉得我忽略了一种更合乎逻辑的方法吗?
猜你喜欢
  • 1970-01-01
  • 2017-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
相关资源
最近更新 更多