【问题标题】:How to avoid a construct being called twice如何避免构造被调用两次
【发布时间】:2021-05-16 13:59:24
【问题描述】:

目前正在尝试学习使用 OOP 和 MVC 模型构建网站的“正确”方法,但由于多年来我主要从事程序性工作,因此显然遇到了一些绊脚石。

(我也是第一次使用 PHP 7,因为我多年来一直坚持使用 PHP 5,所以也尝试使用 mysqli_ 而不是旧的 mysql_ 编写“正确”的方式。学习准备好的语句第一次也不仅仅是逃避我所有的变量,但这是一个完全不同的讨论)

现在我有几个不同的课程:

config.class.php -> Config -> 设置数据库连接和其他站点设置
leads.class.php -> Leads 扩展 Config -> 根据请求(当有人访问网站时)从数据库获取潜在客户信息
questions.class.php -> Questions 扩展 Config -> 获取问题信息(这是一个调查网站)
leadsview.class.php -> - > LeadsView 扩展 Leads -> 如果需要,显示潜在客户信息
questionsview.class.php -> QuestionsView extends Questions -> 从数据库中提取问题信息后在页面上显示问题信息

所以,假设在我的 index.php 上,我需要同时实例化 QuestionsViewLeadsView,以便我可以分别在页面上显示问题和潜在客户信息。所以我这样做:

session_start();
include_once 'lib/autoload.php'; // class autoloader
$l = new LeadsView();
$q = new QuestionsView();

到目前为止一切正常。但是 - 在我的 Config 类中,我不仅有一个数据库连接,还有一个构造函数中的一些站点配置设置,当有人第一次点击页面时需要设置这些设置。到目前为止是这样的:

class Config {
  // set up db connection
  private $db_host;
  private $db_user;
  private $db_password;
  private $db_name;
  protected $conn;
  protected $flow_id;
  protected $domain;

  public function __construct() {
    $this->flow_id = $_REQUEST['flow'];
    $this->domain = $_SERVER['HTTP_HOST'];
    $this->connect(); // open the db connection

    print "hey<br>";
  }

  protected function connect($db = "default") {
    switch ($db) {
      // allow for different db connections in the future
      case "default":
        $this->db_host = "XXXX";
        $this->db_user = "XXXX";
        $this->db_password = "XXXX";
        $this->db_name = "XXXX";
      break;
    }

    $this->conn = new mysqli($this->db_host, $this->db_user, $this->db_password, $this->db_name);
    $this->conn->set_charset("utf8mb4");

    if ($this->conn->connect_error) {
      die("Error connecting to db: " . $this->conn->connect_error);
    }
  }
}

我输入了print "hey&lt;br&gt;"; 只是为了确保构造函数正在运行。但现在它运行了两次:一次来自我的$l = new LeadsView();,一次来自$q = new QuestionsView();,因为它们都扩展了 Config。出于显而易见的原因,我不需要或不想运行该构造函数两次。

所以我的问题是:在这样的场景中设置配置类的正确方法是什么?我是否应该创建一个与 Config 分开的 Dbh 类,并且只让我所有的问题、线索等类扩展 Dbh,这样它们就不会全部运行 Config 方法?还有其他一些我完全想念的明显方法吗?

【问题讨论】:

标签: php class oop constructor


【解决方案1】:

你的类不应该从ConfigDatabase 类或类似的东西扩展。这不是多态性的工作原理。

事实上,您的Config 类并不是很有用。要使用此类,您需要实际帮助您执行准备好的语句的方法。 connect() 方法是不需要的,你肯定不需要所有的属性。

如果我们要修复这个类,那么我们可以这样做:

class Database {
  protected $conn;
  protected $flow_id;
  protected $domain;

  public function __construct(string $db) {
    $this->flow_id = $_REQUEST['flow'];
    $this->domain = $_SERVER['HTTP_HOST'];

    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    // Load the variable from the config file
    $this->conn = new mysqli($db_host, $db_user, $db_password, $db_name);
    $this->conn->set_charset("utf8mb4");

  }
    //
    // The rest of your database abstraction methods. Some methods that help you write parameterized queries more easily
    // Without other methods this class would be useless!
}

类的名称没有意义。它不是一个配置类。它是对 mysqli 的抽象。配置详细信息应存储在单独的文件中。

当您需要在另一个类中使用该类时,只需将其作为参数。

$db = new Database();
$l = new LeadsView($db);

这称为依赖注入。 在使用 OOP 时,您应该在代码中使用这种模式,因为它会使您的类之间的许多交互变得更加简单。您还可以实现 IoC 容器。 Nette 有很好的教程,不过你也可以使用their implementation

我强烈建议不要重新发明轮子。已经有很好的库提供围绕 PDO 的抽象。是的,PDO 不是 mysqli。除非您有充分的理由使用 mysqli,否则不要在 mysqli 上浪费时间。将 PDO 与抽象库一起使用,例如 EasyDB

【讨论】:

  • 感谢您的描述性回答。我读过一些关于 mysqli vs PDO 的文章,并认为坚持使用 mysqli 是最容易的,但我想情况并非如此。而且听起来我最好使用框架而不是从头开始构建?我的很多开发者朋友都在使用 Laravel,我一直在避免使用 Laravel,但我想也许是时候硬着头皮弄清楚了,因为它可能会做我需要做的一切,甚至更多。
  • 我绝对推荐 Laravel 或任何其他流行的框架
【解决方案2】:

您正在使用继承。您可能想改用合成。具体来说,这意味着将Config 提供给LeadsViewQuestionsview

$config = new Config();
$leadsview = new LeadsView( $config );
  
class Config {
  __construct() {
    // do whatever
  }
}

class LeadsView {
  private $config;

  __construct( $config ) {
    $this->config = $config;
  }

  // use this->config somewhere in Leadsview to get whatever you need
}

为防止使用多个 Config 实例,您可以使用单个引用(这需要您的纪律强制执行)。

否则,您可以将配置创建为单例,这样可以保证只存在一个版本的 Config。如果您想了解更多关于 Singleton 的信息,您可以查看它,这是一种众所周知的模式。

【讨论】:

    猜你喜欢
    • 2021-10-09
    • 2021-12-14
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    • 2012-06-11
    相关资源
    最近更新 更多