我有一个用PHP编写的自定义CMS系统。我几乎完成了将所有旧的遗留mysql_函数转换为PDO。 但是,我在一个文件中有很多函数,没有类包装器。文件中只有大约50个函数,它们实际上是运行CMS所需的每个函数。很多天前,我养成了使用全局变量的坏习惯:
function getWidgets($widget_id){
global $db, $BLOG_ID;
$stmt = $db->prepare("SELECT * FROM widget_assoc WHERE bid=? AND aid=?");
$stmt->execute(array($BLOG_ID, $widget_id));
$matches = $stmt->rowCount();
if($matches !== 0){
for($i = 0; $path[$i] = $stmt->fetch(); $i++) ;
array_pop($path);
return $path;
}
}
$ db和$ BLOG_ID等变量需要保持不变,因为许多函数都依赖于这两个变量(还有一些变量) 我不确定这个清理工作的最佳方式。 我可以将整个函数文件包装成一个类吗? 我是否必须将所有输出变量从函数更改为$ this-> ?
我正试图找到一种无痛的方法来删除所有全局变量,而不必重写解析主题中函数输出的所有函数和模板。
我已经阅读了很多关于全局变量最近如何变坏的内容,但我似乎无法用简单的方式来实现这一目标。如果不对我的代码进行大量的过度操作,这可能是不可能的。那就是我在这里的原因!感谢。
编辑: 我使用在每个CMS页面的标题中调用的config.php。此配置文件包含$ BLOG_ID ='12'之类的变量;并在站点构建时动态创建。这些变量可供所有页面使用,但为了将它们放入我的函数中,我必须使用全局。我没有任何类的经验,并且错误地将一个函数文件中的许多函数放在没有类的情况下。
答案 0 :(得分:3)
您可以采用不同的方法来解决这个问题,具体取决于您希望花多少时间来完成这项工作以及如何"以及#34;你想要这样做。
您可以按照假设它们正常工作的方式保留方法。根据你关于不想重写所有内容的评论,这可能是你最好的方法。
在一天结束时,在所有函数中使用全局变量(在我看来)与包含50个没有类的单独函数的文件相比,没有或多或少有不好的做法。
如果将全局变量更改为函数参数,则可以让您深入了解变量的值以及调用方法时变量的来源,然后将变量传递给方法并删除对全局变量的需要。
这可能是最好的"方法,但也是最长的实现方法。无论如何,我建议你这样做是诚实的。
因此,假设您的50方法文件包含用于不同目的的各种方法,您可能决定需要1,2或3个基类和5-10个具有目的或角色的类,例如您可能有一个抽象设置PDO(DB类)连接的基类,然后您的Blog类(示例)可能会扩展Base类。这样,Blog类将继承生成Blog条目所需的所有外部依赖项(外部意味着Blog类可能假定其目的是仅检索,格式化并输出Blog帖子 - 应该已经处理了DB连接)。
一个实际的例子可能是这样的:
/**
* Handle your database connection, querying etc functions
*/
class DB {
protected $_pdo;
public function getPdo() {
if (is_null($this->pdo)) {
$this->_pdo = new PDO(...);
}
return $this->_pdo;
}
public function __construct() {
return $this->getPdo();
}
public function query($sql, $binds = []) {
// write a function that executes the $sql statement on the
// PDO property and return the result. Use $binds if it is not
// empty
$eg = $this->getPdo()->prepare($sql);
return $eg->execute((array) $binds);
}
/**
* Create a basic framework for all purpose-classes to extend
*/
abstract class Base {
/**
* "DB" property might be broad here to cover other DBs or connection
* methods (in theory)
*/
protected $_db;
public function __construct() {
$this->_db = new DB;
}
public function db($sql, $binds) {
return $this->_db->query($sql, $binds);
}
// insert other common methods here that all type-specific classes
// can use
}
现在执行特定的行动/角色:
class Blog extends Base {
public function get($blogId = null) {
// Basic error check
if (empty($blogId)) {
throw new UnexpectedValueException('Blog post ID was missing!');
}
return $this->db('SELECT * FROM `blogposts` WHERE blog_id = ?', $blogId);
}
}
注意我还没有对此进行过测试,但现在的原则是Blog类只包含特定于Blog帖子的逻辑。任何格式化函数,安全性函数等可以在Base类中,也可以在Base类与DB类似的另一个辅助类中使用,例如,一个Formatter类。
你应该能够做到这一点:
<?php
# blogPost.php
# - Gets a blog post
require_once 'common.php'; // <--- include your class files, or an autoloader
// Instantiate the class for this role
$blog = new Blog;
// Get the blog post
$id = (isset($_GET['id'])) ? (int) $_GET['id'] : null;
$post = $blog->get($id);
// now other methods:
$post->toHTML(); // example - function might call a template file, insert the
// DB results into it and output it to the browser
这只是一个粗略的例子,但展示了如何构建一组类来实现具有单一角色的类的原则,以及具有单一目的的方法(例如&#34;通过其ID&#34;)获取博客文章。
这样,扩展Base的所有内容都将自动访问数据库(通过继承)。如果要尝试从实现中删除SQL,可以向DB类添加一些提供基本ORM的方法。
另一个简短/快速选项是创建一个单独的类,它可以为您所包含文件中的所有函数提供任何通用内容,在本例中为数据库处理程序和博客文章ID。例如:
class Common {
protected static $_db;
protected static $_blogId;
public function getDb() {
if (is_null(static::$_db)) {
static::$_db = new PDO(...);
}
return static::$_db;
}
public static function getBlogId() {
return (int) static::$_blogId;
}
public static function setBlogId($id) {
static::$_blogId = (int) $id;
}
}
现在您只需要在开始调用函数之前实例化此类,并设置博客帖子ID(如果需要)。只要需要,就会懒惰地创建PDO连接。
# functions.php
require_once 'common.php';
function getWidgets($widget_id) {
$stmt = Common::getDb()->prepare('SELECT * FROM widget_assoc WHERE bid = ? AND aid = ?');
$stmt->execute(array(Common::getBlogId(), $widget_id));
$matches = $stmt->rowCount();
if ($matches !== 0) {
for($i = 0; $path[$i] = $stmt->fetch(); $i++);
array_pop($path);
return $path;
}
}
此处您唯一的责任是在每个页面上设置博客帖子ID,例如:
# blogPost.php
require_once 'common.php';
// Manual dependency blog ID needs to be set before processing:
$blogId = isset($_GET['blog_id']) ? (int) $_GET['blog_id'] : null;
Common::setBlogId($blogId);
// now you call your processing methods and perform your logic flow
答案 1 :(得分:2)
如果要在多个位置使用变量,可以为这些变量创建单例。
class Config
{
/**
* @var Singleton The reference to *Singleton* instance of this class
*/
private static $instance;
public $db = 'db';
public $BLOG_id = 'id';
/**
* Returns the *Singleton* instance of this class.
*
* @return Singleton The *Singleton* instance.
*/
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Protected constructor to prevent creating a new instance of the
* *Singleton* via the `new` operator from outside of this class.
*/
protected function __construct()
{
}
}
//To use it
$config = Config::getInstance();
$config->db;