【问题标题】:Set a php object global for query optimization为查询优化设置一个全局的 php 对象
【发布时间】:2013-08-04 07:43:46
【问题描述】:

我在优化我的 PHP 脚本时遇到了问题。例如:

一个 MySQL 表:

选项名称 ||选项值 ==================================================== === 基本网址 || http://mysite.com/myproject 主题名 ||默认 语言 || zh

MyScript.php 文件:

class options {
  private $options = null;
  public function get($optionName) {
    if(!isset($this->options))
        self::get_data();
    return $this->options[$optionName];
  }
  protected function get_Data() {
    // ...
    // DO A MYSQL QUERY AND SAVE IT TO $this->options
    // ...
  }
}

这个类返回的数据是常量。因此,每次我需要访问例如 base_url 值时,都不需要运行 MySQL 查询。 创建对象并在全局范围内使用它的最佳方式是什么?

$OPTIONS = new options;
function load_option($optName) {
  global $OPTIONS;
  return $OPTIONS->get($optName);
}

可能有类似这个功能的东西?有人说这是最糟糕的方法

我需要帮助。谢谢!

【问题讨论】:

  • 他们有没有告诉你为什么这是最糟糕的方式?我通常会忽略那些没有给我正确论据的人,即使他们是对的。
  • self::get_data(); 这不会抛出 E_STRICT,因为 get_data() 不是静态的
  • 请停止使用全局变量。谁告诉你你的方法是“最糟糕的方法”,他是完全正确的。
  • @tereško 听起来你就是这样一个人,在没有给出好的论据和适当的替代方案的情况下大喊某件事是最糟糕的方式。我知道你是对的,但你仍然没有帮助。

标签: php oop query-optimization


【解决方案1】:

您的问题是您不了解什么是 SOLID 和 DI 原则。您应该实现为每个单一职责服务的类,然后按需注入它们的实例。

在你的情况下,它看起来像这样,

class Config
{
    protected $pdo;

    protected $cache;

    public function __construct($pdo)
    {
       $this->pdo = $pdo;
    }

    public function read($key)
    {
        // Read a value by its key from a table
        // Here should be a SELECT query

        // You can also prevent reading the same thing twice
        // by storing it in a cache
    }

    public function write(array $data)
    {
        foreach ($data as $key => $value) {

            // Here should be INSERT statement
        }
    }

    public function delete($key)
    {
         // Here comes a DELETE statement
    }
}

每次需要读取配置值时,只需将Config 的实例注入需要它的类即可。

class Foo
{
     protected $config;

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

     public function doSomethingDependingOnConfig()
     {
         if ($this->config->read('lang') === 'en') {
            // do something
         }
     }
}

你会像这样使用它,

$pdo = new PDO(...);

$config = new Config($pdo);

// Test
echo $config->read('lang'); //en

// So,
$foo = new Foo($config);

$foo->doSomethingDependingOnConfig();

【讨论】:

    【解决方案2】:

    实际上,我不认为这是最糟糕的方式。

    许多配置设置不需要存储在数据库中。有些甚至不能(例如数据库的地址和凭据)。

    所以很明显,一些硬编码的配置很方便。如果您调查现有的 PHP 应用程序,您会发现它们中的大多数都有一些全局可配置的选项。

    全局变量的缺点是它非常严格并且很难改变它的用法。很快您就会发现自己在整个应用程序中都使用了这个全局变量。

    但是您已经通过将对其的访问包装在一个函数中来反驳这一点,因此您可以在以后轻松更改选项,而无需更改整个应用程序。通过制作这个包装函数,您已经隐藏了选项的存储方式。如果您愿意,您仍然可以从数据库中获取它们,或者开始将它们存储在文件中,因为您需要更改的只是这个函数。所以这实际上是一个很好的解决方案。

    您可以做一件事来改进此代码:

    也许你可以将它包装在一个 Config 单例类中。这样做的好处是,您实际上也可以将配置存储在该类中,摆脱全局变量,从而摆脱对该全局变量的意外访问。您将强迫自己始终使用函数/类访问选项。

    【讨论】:

    • 单例与全局变量有何不同?
    • @tereško 单例类可以在私有变量中包含配置设置,只公开检索它们的方法。这样,您可以完全隐藏实际的配置变量,而不是拥有一个全局数组。所以这个解决方案和现在的类似,有一个读取配置的函数,只是目前还可以访问全局变量本身,这就是单例类的优势所在。
    • Singleton 是一个封装在类中的全局变量。它只是一种不同形式的全局状态。这就是为什么这是一种非常糟糕的做法。
    • @tereško 虽然我不会说“非常”,但我同意单例通常是不好的做法,因为你说的确切原因是:单例比全局好一点。但是在某些情况下,一个类的两个实例确实是不可取的,在这种情况下,单例是完美的。单例是一种被广泛接受的设计模式是有原因的。并不是说你应该把所有东西都放在一个单例中,但在某些情况下这是最好的解决方案。
    • @tereško 对于这样的应用程序配置,这是值得商榷的,但是说它非常糟糕的做法通常是过早下结论。但我想听听你的选择,因为我是第一个承认在这种情况下会有很多其他选择的人。
    猜你喜欢
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    相关资源
    最近更新 更多