PHP 结构 - 接口(interface)和 stdClass 变量

标签 php oop

我正在构建一个类来处理 Paypal IPN 作为项目的一部分,因为我已经知道我将需要在至少两个即将到来的工作中再次使用它 - 我想确保我构建它以一种允许我重新使用它而无需重新编写类代码的方式 - 我只想处理业务逻辑中的更改。

问题的第一部分是re。接口(interface)。我还没有完全掌握它们的用处以及何时/何地部署它们。如果我有我的类文件(“class.paypal-ipn.php”),我是否在该文件中实现接口(interface)?

这是我目前正在使用的(功能列表不完整,但仅供说明):

CLASS.PAYPAL-IPN-BASE.PHP

interface ipn_interface {

    //Database Functions
    // Actual queries should come from a project-specific business logic class
    // so that this class is reusable.

    public function getDatabaseConnection();
    public function setDatabaseVars($host="localhost",$user="root",$password="",$db="mydb");
    public function dbQuery($SQL);

    //Logging Functions

    public function writeLog($logMessage);
    public function dumpLogToDatabase();
    public function dumpLogToEmail();
    public function dumpLogToFile();

    //Business Logic Functions

    private function getTransaction($transactionID);

    //Misc Functions

    public function terminate();
}

class paypal_ipn_base {

    //nothing to do with business logic here.

    public function getDatabaseConnection() {
    }

    public function setDatabaseVars($host="localhost",$user="root",$password="",$db="mydb") {
    }

    public function dbQuery($SQL) {
    }

}

CLASS.PAYPAL-IPN.PHP

final class paypal_ipn extends paypal_ipn_base implements ipn_interface {

    //business logic specific to each project here

    private function getTransaction($transactionID) {

       $SQL = "SELECT stuff FROM table";
       $QRY = this->dbQuery($SQL);

       //turn the specific project related stuff into something generic

       return $generic_stuff; //to be handled by the base class again.

    }

}

用法

在这个项目中:

  • 需要基础类和业务逻辑类的类文件。
  • 实例化*paypal_ipn*
  • 编写代码

在其他项目中:

  • 复制基础 IPN 类
  • 在接口(interface)的约束下编辑/重写业务逻辑类 *paypal_ipn*。
  • 实例化*paypal_ipn*
  • 编写代码

如您所见,我实际上只是用它来定义相关函数组并添加注释。它使阅读更容易,但它对我有什么(如果有的话)其他好处 - 是不是我可以将扩展程序和基类放在一起并在缺少某些内容时强制出错?

stdClass 问题

问题的第二部分是建立在可读性方面。在类本身中,存储变量的数量不断增加,有些是在构造函数中设置的,有些是通过其他函数设置的——它们与诸如保存数据库连接变量(和连接资源本身)、代码是否应该运行等事情有关在测试模式下,日志设置和日志本身,等等......

我已经开始像往常一样构建它们(同样,下面是不完整的&用于说明):

$this->dbConnection = false;
$this->dbHost = "";
$this->dbUser = "";
$this->enableLogging = true;
$this->sendLogByEmail = true;
$this->sendLogTo = "user@domain.com";

但后来我发现不断增长的列表可能需要一些结构,所以我将其调整为:

$this->database->connection = false;
$this->database->host = "";
$this->database->user = "";
$this->logging->enable = true;
$this->logging->sendByEmail = true;
$this->logging->emailTo = "user@domain.com";

当我在编码和测试时转储整个类时,这让我更容易阅读变量列表。

完成后,我计划为通用类编写一个特定于项目的扩展,我将在其中保留查询的实际 SQL - 从一个项目到另一个项目,Paypal 的 IPN 过程和逻辑不会改变 - 但每个项目的数据库结构会,因此对类的扩展会将所有内容清理回单一格式,因此基类不必担心它,并且一旦编写就永远不需要更改。

所以总而言之只是一个理智检查 - 在我走得太远之前,这看起来是正确的方法吗?

最佳答案

如果您正在使用我强烈推荐的类自动加载器,您不会希望将接口(interface)和类保存在同一个文件中,这样接口(interface)就可以自动加载,而无需首先加载实现它的这个类。

有关自动加载的更多信息: http://php.net/manual/en/language.oop5.autoload.php

您可能需要考虑的另一件事是,给定的类可能会实现多个接口(interface),而多个类可能会实现相同的接口(interface)。

接口(interface)主要用于各种设计模式、执行规则以及将类与任何依赖类分离。当您将一个类与其依赖项分离时,以后修改代码会变得更加容易。

例如,假设您有一个类 A,它接受另一个类 B 作为参数,并且该类遍布您的代码。您想要强制只有具有特定方法子集的类才能被接受为该参数,但您不想将输入限制为一个具体类及其后代。将来,您可能会编写一个完全不同的类,它不扩展类 B,但可用作类 A 的输入。这就是您要使用接口(interface)的原因。它是类之间的可重用契约。

有些人会争辩说,由于 PHP 是一种动态语言,接口(interface)是一种不必要的复杂化,可以使用鸭子类型来代替。然而,我发现在大型多用户代码库中,接口(interface)可以节省大量时间,让您更多地了解一个类如何使用另一个类,而无需深入研究代码。

如果您发现自己有一大堆必须在对象或函数之间传递的变量,它们通常最终都应该有自己的类,但每种情况都是不同的。

-- 依赖注入(inject)示例 --

class A implements AInterface {
    public function foo($some_var) {}
}

interface AInterface {
    public function foo($some_var);
}

class B {
    protected $localProperty;

    // inject into the constructer. usually used if the object is saved in a property and used throughout the class
    public function __construct(AInterface $a_object) {
        $this->localProperty = $a_object;
    }

    // inject into a method. usually used if the object is only needed for this particular method
    public function someMethod(AInterface $a_object) {
        $a_object->foo('some_var');
    }
}

您现在可以看到您可以编写另一个类来实现 foo 方法(和 AInterface)并在类 B 中使用它。

举一个现实世界的例子(经常使用),假设您有一个数据库类,其中包含与数据库交互的特定方法(getRecord、deleteRecord)。现在假设您稍后找到切换数据库 rdbms 的理由。您现在需要使用完全不同的 SQL 语句来实现相同的目标,但是由于您为类型提示使用了一个接口(interface),您可以简单地创建一个新类来实现该接口(interface),但在交互时以完全不同的方式实现这些相同的方法使用不同的 rdbms。在创建这个新类时,您将确切地知道需要为这个新类编写哪些方法,以适应需要使用数据库对象的相同对象。如果您使用用于创建对象并将它们注入(inject)其他对象的容器类,则无需更改太多应用程序代码即可切换数据库类,从而切换数据库 rdbms。您甚至可以使用工厂类,它可以将您的更改限制在一行代码中以进行此类更改(理论上)。

关于PHP 结构 - 接口(interface)和 stdClass 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6216801/

相关文章:

php - 方法语法 "public function direct(){}"在 PHP 中如何工作?

PHP:Twig:图像的相对路径?

java - 强制客户端关闭对象

java - 状态命令模式

PHP 子类不能实现相同的接口(interface)父类实现

php - 调用未定义的方法 Illuminate\Database\Query\Builder::unique()

javascript - 随着购物车数量的增加或减少,计算每行的总价。 (数量*价格)

php - 获取Youtube视频标题,说明和缩略图时出错

javascript - *在*构造函数中声明的属性在实例中可见。为什么?

java - 是否有使用 DTO 的模式而不必复制域对象的属性?