停止在 PHP 中使用“global”

2023-11-25

我有一个config.php包含在每个页面中。在配置中我创建了一个看起来像这样的数组:

$config = array();
$config['site_name']      = 'Site Name';
$config['base_path']      = '/home/docs/public_html/';
$config['libraries_path'] = $config['base_path'] . '/libraries';
//etc...

然后我有function.php,这也包含在几乎每个页面中,我必须在其中使用global $config访问它 - 并且this这就是我想摆脱的!

我如何访问$config在我的代码的其他部分而不使用global?

谁能解释一下,WHY我不应该使用global在我的例子中?有人说这是不好的语气,有人说这不安全?

EDIT 1:

我在哪里以及如何使用它的示例:

function conversion($Exec, $Param = array(), $Log = '') {
    global $config;
    $cmd = $config['phppath'] . ' ' . $config['base_path'] . '/' . $Exec;
    foreach ($Param as $s)
    {
        $cmd .= ' ' . $s;
    }
}

EDIT 2:

按照建议将所有这些都放在课堂上Vilx,会很酷,但在这种情况下,我如何将它与提取配置的以下循环联系起来key and value来自数据库。
我过于简单化了分配的想法$config数组,这是一个例子:

$sql = "SELECT * from settings";
$rsc = $db->Execute($sql);
if ( $rsc ) {
    while(!$rsc->EOF) {
        $field = $rsc->fields['setting_options'];
        $config[$field] = $rsc->fields['setting_values'];
        @$rsc->MoveNext();
    }
}

EDIT 3:

此外,我还必须访问其他vars来自配置中设置的函数,其中很少,例如:$db, $language等等。

如果我把它们放在课堂上真的能解决任何问题吗?如果我使用global它真正改变了什么?

EDIT 4:

I read PHP 全局函数 where Gordon以非常好的方式解释为什么你不应该使用global。我同意一切,但我不使用global就我而言,重新分配变量,这将导致,就像他说的那样,<-- WTF!!, ;)) 是的同意,这太疯狂了。但是如果我只需要通过使用函数来访问数据库global $db这种情况下问题出在哪里呢?否则,在不使用的情况下,你如何做到这一点global?

EDIT 5:

在同一个 PHP 全局函数中deceze says: “反对全局的一个重要原因是,它意味着该函数依赖于另一个作用域。这很快就会变得混乱。”

但我在这里谈论的是基本的“INIT”。我基本上设定define但使用vars- 这在技术上是错误的。但是你的函数不依赖于任何东西 - 除了一个变量的名称$db你能记住吗?确实是全球都需要使用$db,这里的 DEPENDENCY 在哪里以及如何使用它?

P.S.我只是有一个想法,我们面临着两种不同思想的冲突,例如:mine(但还没有很好地理解面向对象编程)以及那些在 OOP 中可以被称为大师(从我目前的观点来看)的人 - 对我来说对他们来说显而易见的事情却产生了新的问题。我认为这就是为什么这个问题被一遍又一遍地问的原因。就我个人而言,它毕竟变得更加清晰,但仍然有一些事情需要澄清。


反对的点global变量的优点是它们与代码的耦合非常紧密。你的整个代码库取决于 a) 变量name $configb) 该变量的存在。如果您想重命名变量(无论出于何种原因),您必须这样做到处整个代码库。您也不能再使用任何独立于该变量的代码段。

示例为global多变的:

require 'SomeClass.php';

$class = new SomeClass;
$class->doSomething();

在上面几行的任何地方,您都可能会收到错误,因为类或某些代码SomeClass.php隐式依赖于全局变量$config。尽管仅查看班级,但没有任何迹象表明这一点。为了解决这个问题,你必须这样做:

$config = array(...);

require 'SomeClass.php';

$class = new SomeClass;
$class->doSomething();

这段代码可能still如果你没有在里面设置正确的键,就会在某个地方失败$config。因为配置数组的哪些部分并不明显SomeClass需要或不需要,以及当需要它们时,很难重新创建正确的环境以使其正确运行。如果您碰巧已经有一个变量,它也会产生冲突$config用于其他任何您想使用的地方SomeClass.

因此,与其创建隐式的、不可见的依赖关系,inject所有依赖项:

require 'SomeClass.php';

$arbitraryConfigVariableName = array(...);

$class = new SomeClass($arbitraryConfigVariableName);
$class->doSomething();

通过显式传递配置数组作为参数,上述所有问题都得到解决。就这么简单传递所需的信息在您的应用程序内。它还使应用程序的结构和流程以及对话内容变得更加清晰。如果您的应用程序目前是一个大泥球,要达到这种状态可能需要进行一些重组。


你的代码库越大,你需要做的事情就越多decouple各个部分彼此分离。如果每个部分都依赖于代码库中的每个其他部分,那么您根本无法单独测试、使用或重用它的任何部分。这只会陷入混乱。要将各个部分彼此分开,请将它们编码为类或函数,将所有必需的数据作为参数。这会在代码的不同部分之间创建干净的接缝(接口)。


尝试将您的问题结合到一个示例中:

require_once 'Database.php';
require_once 'ConfigManager.php';
require_once 'Log.php';
require_once 'Foo.php';

// establishes a database connection
$db = new Database('localhost', 'user', 'pass');

// loads the configuration from the database,
// the dependency on the database is explicit without `global`
$configManager = new ConfigManager;
$config = $configManager->loadConfigurationFromDatabase($db);

// creates a new logger which logs to the database,
// note that it reuses the same $db as earlier
$log = new Log($db);

// creates a new Foo instance with explicit configuration passed,
// which was loaded from the database (or anywhere else) earlier
$foo = new Foo($config);

// executes the conversion function, which has access to the configuration
// passed at instantiation time, and also the logger which we created earlier
$foo->conversion('foo', array('bar', 'baz'), $log);

我将把各个类的实现作为读者的练习。当您尝试实现它们时,您会发现它们的实现非常简单明了,并且不需要任何操作global。每个函数和类都获取以函数参数形式传递的所有必需数据。显然,上述组件可以以任何其他组合插入在一起,或者依赖项可以轻松地替换为其他组件。例如,配置根本不需要来自数据库,或者记录器可以记录到文件而不是数据库而无需Foo::conversion必须了解所有这些。


示例实现ConfigManager:

class ConfigManager {

    public function loadConfigurationFromDatabase(Database $db) {
        $result = $db->query('SELECT ...');

        $config = array();
        while ($row = $result->fetchRow()) {
            $config[$row['name']] = $row['value'];
        }

        return $config;
    }

}

这是一段非常简单的代码,甚至没有做太多事情。您可能会问为什么要将其作为面向对象的代码。关键是,这使得使用该代码变得非常灵活,因为它将它与其他所有代码完美地隔离开来。你给出一个数据库连接,你就会得到一个具有特定语法的数组。输入→输出。清晰的接缝、清晰的接口、最小的、明确的职责。您可以使用一个简单的函数执行相同的操作。

对象的额外优点是它甚至可以进一步解耦调用的代码loadConfigurationFromDatabase来自该函数的任何特定实现。如果你只是使用全局function loadConfigurationFromDatabase(),您基本上又遇到了同样的问题:当您尝试调用该函数时需要定义该函数,并且如果您想用其他东西替换它,则会出现命名冲突。通过使用对象,代码的关键部分移至此处:

$config = $configManager->loadConfigurationFromDatabase($db);

你可以替代$configManager这里是为了任何其他物体也有一个方法loadConfigurationFromDatabase。这就是“鸭子打字”。你不在乎具体是什么$configManager是的,只要有方法loadConfigurationFromDatabase。如果它走路像鸭子,叫起来像鸭子,那么它就是鸭子。或者更确切地说,如果它有一个loadConfigurationFromDatabase方法并返回一个有效的配置数组,它是某种 ConfigManager。您已将代码与一个特定变量解耦$config,从一个特定的loadConfigurationFromDatabase函数,甚至从一个特定的函数ConfigManager。所有部分都可以从任何地方动态更改、换出、替换和加载,因为代码不依赖于任何特定的其他部分。

The loadConfigurationFromDatabase方法本身也不依赖于任何一个特定的数据库连接,只要它可以调用query并获取结果。这$db传递给它的对象可能完全是假的,并且可以从 XML 文件或其他任何地方读取其数据,只要它是界面行为仍然相同。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

停止在 PHP 中使用“global” 的相关文章

  • 如何配置 nginx 重写规则以使 CakePHP 在 CentOS 上运行?

    大家好 请帮帮我 我正在尝试在运行 Nginx 和 Fact CGI 的 Centos 服务器上设置 cakephp 环境 我已经在服务器上运行了一个 WordPress 站点和一个 phpmyadmin 站点 因此我已经正确配置了 PHP
  • 在多维数组 PHP 的所有键中搜索

    我想在多维数组中的所有键中搜索特定字符串 我只需要弄清楚它是否存在 仅此而已 我想知道访问者的 IP 是否存在于任何数组中 有没有我可以用来执行此操作的 php 函数或方法 我尝试过的每个函数或方法总是返回 false 数组中 数组搜索 数
  • AWS S3从本地主机批量上传php错误

    我在尝试着批次 散装从本地主机 xampp 上传到我的S3 bucket 它似乎适用于大约 6 个项目 然后我收到一条错误消息 cURL 错误说Failed sending network data from http curl haxx
  • Facebook“赞”按钮回调帮助

    我正在使用此代码进行类似 facebook 的回调 问题是 如果我调用 php 脚本 例如 有人可以看到我的 javascript 并运行此页面 甚至可以向其发送垃圾邮件或在没有先点赞的情况下使用它 我的想法是 我想为每个喜欢该页面的用户提
  • YUI压缩机或类似的PHP?

    我一直在我的测试服务器上使用 yuicompressor jar 来动态最小化已更改的 JavaScript 文件 现在我已经将网站部署到公共服务器上 我注意到服务器的策略禁止使用 exec 或其等效项 因此我不再执行 java 有没有一个
  • use 语句顺序会影响 PHP 中的功能吗?

    我使用 PHP 的命名空间已经有一段时间了 我认为它对我的编程来说是一个很好的补充 今天早上我想知道一些关于use陈述 我想知道顺序是否use影响我的 PHP 代码的功能 根据 PHP net 使用别名引用外部完全限定名称或导入的能力是命名
  • 随机错误 symfony:ContextErrorException: 警告: simplexml_load_file(): I/O 警告: 无法加载外部实体

    在我的 Symfony 项目中 当我进入应用程序中的随机页面时 会出现以下随机错误 ContextErrorException Warning simplexml load file I O warning failed to load e
  • Memcache 不会刷新或清除内存

    我一直在尝试清除我的内存缓存 因为我注意到使用时存储占用了近 30 的服务器内存ps aux 所以我运行了以下 php 代码 memcache new Memcache memcache gt connect localhost 11211
  • PHP 中的静态类初始值设定项

    我有一个带有一些静态函数的辅助类 类中的所有函数都需要一个 重 初始化函数来运行一次 就好像它是一个构造函数 有实现这一目标的良好实践吗 我唯一想到的就是打电话init函数 如果它已经运行过一次 使用静态 initialized变种 问题是
  • CryptoJS 使用密码加密 AES,但 PHP 解密需要密钥

    我在用CryptoJS https code google com p crypto js AES加密字符串 function doHash msg msg String msg var passphrase aggourakia var
  • 在另一个文件中扩展类的正确方法是什么?

    这就是我在 foo php 中的内容 class Foo public foo NULL public foo2 NULL public function setFoo foo foo2 this gt foo foo this gt fo
  • 写入 xml 文件时允许的内存大小已耗尽(尝试分配 4459414 字节)[重复] 67108864 字节

    这个问题在这里已经有答案了 可能的重复 php 中允许的内存大小已耗尽 尝试分配 43148176 字节 33554432 字节 https stackoverflow com questions 415801 allowed memory
  • Apache 子进程已退出,状态为 255

    经过大量的搜索 尝试 修复 等待和哭泣 在我放弃之前 我想为这个错误抓住最后的机会 我们正在奔跑Microsoft Windows Server 2012 Apache 2 4 6 Win64 OpenSSL 1 0 1e PHP 5 5
  • 错误 #520009 - 帐户受到限制

    我收到 520009 错误 帐户 电子邮件受保护 cdn cgi l email protection被限制 当尝试进行并行付款时 我的代码使用沙箱运行良好 但我切换到实时端点 它开始失败 有问题的帐户是有效的 PayPal 帐户 我使用的
  • 在 PHP 中将整数转换为十六进制值

    如何将PHP中第一类中的数字转换为第二类中的数字 是否有内置函数来转换数字 也是我的标题 将整数转换为十六进制值 甚至正确 class Permission const READ 1 const UPDATE 2 const DELETE
  • 当路由不存在时重定向 laravel 4

    我正在使用 laravel 4 当我的项目处于生产模式时 我得到 抱歉 找不到您要查找的页面 当我到达一条不存在的路线时 当我 grep 我的代码时 它在两个地方找到 vendor symfony debug Symfony Compone
  • 彩色 var_dump() 和错误

    我怎样才能将样式设置为var dump 功能和PHP错误样式 如下图所示 目前我有下一个观点var dump with pre var dump pre 没有它将全部在一行中 并且只是纯文本的错误 我搜索了一些 PHP 颜色错误 var d
  • Lumen:无法打开流:.../vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php:107 中的权限被拒绝

    My OS is ubuntu 16 04 and I am running Lumen 5 5 When I try to run the app in the browser I get an error 500 我在 var log
  • 管理产品页面自定义字段显示在购物车和结账中

    我在产品页面的常规设置选项卡上的 WooCommerce 管理中创建了一个自定义字段 以插入几天的制造时间 我想在购物车和结帐页面上每个产品名称上方显示此自定义字段值 这是我的代码 Insert a Custom Admin Field f
  • Google Drive 服务帐户上传的位置

    我正在尝试使用服务帐户将文件上传到我的 Google 云端硬盘 当我部署此代码时 我不希望用户给予授权 我希望他们上传到我的帐户 我通过 PHP 使用它 下面是我到目前为止的情况 这段代码是基于官方文档给出的例子 当我运行 php 脚本时

随机推荐

  • iOS Safari/Chrome 中的 Cookie 持久性

    当我关闭并重新打开 iOS Safari 和 Chrome 上的浏览器时 我的持久 cookie 将被删除 我使用的是 iOS 11 但也在 iOS10 9 上进行了测试 Cookie 在 Android 和桌面上正确保留 奇怪的是 它在
  • 使用 C# 的媒体基础

    媒体基金会是微软推荐的技术 它确实通过大量示例和解释来支持它 但全部都是本机代码 我发现了一个包装纸来源锻造让我能够将 Media Foundation 与 C 一起使用 但当我阅读人们谈论的内容时 并非所有事情都可以通过托管代码完成 我有
  • 网络参考和服务参考之间的区别?

    WCF 中的 Web 引用和服务引用有什么区别 WCF 中哪一个更可取 这里的低级答案是 Web 引用将创建一个客户端代理类 该类允许您的代码与通过 WSDL 描述的 Web 服务对话 并通过 SOAP 或 HTTP GET 进行通信 其他
  • Docker 更改活动容器上的已发布端口

    例如 我想更改活动容器上已发布的端口 docker run p 80 80 name nginx live nginx 然后稍后将其更改为另一个端口 例如 p 8080 80 Docker 没有一种机制可以在容器启动后更改其已发布的端口 当
  • 如何在 Objective-C 中将字符串中的英文数字转换为波斯语/阿拉伯语数字?

    我有一个英文字符串 可能有数字 也可能没有数字 但我希望这些数字作为波斯数字打印在屏幕上 例如如果NSString foo a string with numbers 1 2 3 那么输出应该是a string with numbers 我
  • 在加载数据之前显示 Ajax 加载器

    你好 朋友们 我想在数据加载之前显示 Ajax 加载器 特别是 div 但问题是数据是动态地出现在同一页面上 但我的脚本从另一个文件调用数据Script php请看下面我的代码 Script
  • GitHub for Mac 同步删除了我未提交的更改

    我在 Mac OS X 10 10 上使用 GitHub for Mac 版本 210 点击 同步 按钮删除了我未提交的更改 这种事应该时常发生吗 直到那时我才遇到过这个问题 尽管我主要使用 Windows 版的 Github 我认为如果我
  • PHP:Laravel 如何急切加载 find 方法

    我有一个模型Users其中有很多Pages 我想急切加载下面的方法 以便它只返回一个用户并立即加载所有页面 我该怎么做 user User find 1 pages user gt pages foreach pages as page v
  • “无法确定要运行哪个“make”命令。检查构建配置中的“make”步骤。” Qt创建者

    我安装了好几次 qt Creator 但它的花费从来没有像我现在的电脑那么高 首先 我使用了 Pendrive 上一直有的安装程序 Qt 5 8 的安装程序 告诉我无法下载某些存储库 我下载了同一安装程序的 5 9 版本 结果相同 在尝试安
  • 未找到 OpenCV 非托管 DLL asp.net

    我们正在构建一个 Web 应用程序 C NET 它使用 Emgu opencv 包装器形式的非托管库 我们强制构建为 32 位 x86 并且我们使用 Emgu 的 32 位版本 所有这些在本地构建上都运行良好 但是当发布到我们的网络服务器时
  • 使用 C++ 和 Windows API 以编程方式更改壁纸

    我一直在尝试使用 Qt 和 mingw32 编写一个应用程序来下载图像并将其设置为背景壁纸 我在网上阅读了几篇关于如何在 VB 和 C 中执行此操作的文章 以及在某种程度上如何在 C 中执行此操作 我目前正在致电SystemParamete
  • 错误:无效的“asm”:在 GCC 中使用内联汇编时,% 字母后缺少操作数编号

    我正在尝试将 MS 的简单汇编代码转换为与 gcc 一起使用 我尝试转换的 MS 汇编代码就在下面 我有两个int变量 number and return mov eax number neg eax return eax 而且 我已经尝试
  • std::regex 线程安全吗?

    相关静态 boost wregex 实例是线程安全的吗 但对于标准化版本 我可以从具有相同正则表达式对象的多个线程调用 regex search 吗 声称std regex在各个方面都是线程安全的 这是一个相当大胆的声明 C 11 标准没有
  • 如何在Python中将RGB图像转换为灰度图像?

    我正在尝试使用matplotlib读取 RGB 图像并将其转换为灰度图像 在 matlab 中我使用这个 img rgb2gray imread image png In the matplotlib 教程他们不涵盖它 他们只是在图像中阅读
  • 如何在 Bootstrap 3 网格系统内分隔这些图像?

    我想知道使用 Bootstrap 3 RC2 使用 CSS 在这 3 个图像之间放置空格的最佳方法是什么 因为我目前所做的不是自动调整图像大小 即使我已将宽度设置为自动 pictureid 标签 我希望他们能够内联并相应地调整图像大小 这是
  • OpenSSL 和 MS CryptoAPI:不同的数字签名

    我使用 makecert 实用程序生成带有私钥的 X509 证书 makecert n CN RootCATest r sv RootCATest pvk RootCATest cer makecert sk MyKeyName iv Ro
  • 带有 proguard 的 Ksoap2

    我有一个使用 ksoap2 库的应用程序 一切正常 但是从 Eclipse 导出应用程序时 它显示了这个 Proguard returned with error code 1 See console Note there were 4 d
  • 保存图形后,图形标签和刻度后面的黑色背景,但不在交互视图中

    我有一个奇怪的问题 如果我保存一个图形 它的标签和刻度线将具有黑色背景 请参阅此示例 plt savefig asdsadsad png 我什至没有在此处包含任何代码 因为这种情况发生在最简单的绘图上 即使我之前使用另一台从未出现过此问题的
  • SQLAlchemy 列到行转换,反之亦然——这可能吗?

    我正在寻找一种仅 SQLAlchemy 的解决方案 用于将从表单提交收到的字典转换为数据库中的一系列行 每个行对应提交的每个字段 这是为了处理不同应用程序之间差异很大的首选项和设置 但是 它很可能适用于创建类似数据透视表的功能 我在 ETL
  • 停止在 PHP 中使用“global”

    我有一个config php包含在每个页面中 在配置中我创建了一个看起来像这样的数组 config array config site name Site Name config base path home docs public htm