2

在我的应用程序架构中,我想用不会烧伤大多数开发人员眼睛的东西来替换我的全局变量,因为我正在使用这样的全局变量,

define('DEVELOPMENT_ENVIRONMENT', true);

// Shorten DIRECTORY_SEPARATOR global,
define('DS', DIRECTORY_SEPARATOR);

// Set full path to the document root
define('ROOT', realpath(dirname(__FILE__)) . DS);

我怎么能防止这种情况?我尝试创建一个读取 xml 文件的类,但这会给我一个更长的代码,像这样

$c = new Config();
if($c->devmode === TRUE) {}

或者可能是这样的

$c = new Config()
echo $c->baseurl;

有没有更好的方法来做到这一点?

4

3 回答 3

1

我认为像您这样的问题通常无法得到回答,但无论如何他们可能都应该得到答案。只是没有一个黄金法则或解决方案来处理这个问题。

在最简单的意义上,我可以想象您描述的问题是应用程序运行的上下文。在人脸层面,这是多方面的,只需要一个常数:

define('DEVELOPMENT_ENVIRONMENT', true);

即使非常简单且易于引入,它的价格也很高。如果它已经是您应用程序的一部分,请首先尝试了解其含义。

您有一个应用程序代码库,并且在其中的某个位置(具体而言,在使用该常量的任何地方)都有代码的分支,如果该常量为TRUE或,则它们将被执行FALSE

这本身就是有问题的,因为这样的代码往往会变得复杂难以调试。因此,无论如何常量、变量、函数、类),您首先应该减少防止此类结构的使用。

老实说,使用(全局)常量对我来说并没有那么错误,尤其是与替代方案相比,它首先是我眼中最可取的一个,因为它的位置更少,也不复杂,而是直截了当。在当前 PHP 版本中,您可以通过使用const关键字声明它来将其转换为动态较少的常量:

const DEVELOPMENT_ENVIRONMENT = TRUE;

这是这一小行代码的一个方面。另一个是它带来的低层次抽象。如果您想为应用程序定义环境,那么说开发环境是真还是假是模棱两可的。相反,您通常有一个可以是不同类型的环境:

const ENVIRONMENT_UNSPECIFIED = 0;
const ENVIRONMENT_DEVELOPMENT = 1;
const ENVIRONMENT_STAGING     = 2;
const ENVIRONMENT_LIVE        = 3;

const ENVIRONMENT = ENVIRONMENT_DEVELOPMENT;

然而,这个小例子只是一个例子,用来形象化我的意思,让它变得有点模棱两可。它不能解决上面概述的一般问题以下问题:

您在全局级别为您的应用程序引入上下文。这意味着组件(函数、类)中与任何全局(此处:)相关的任何代码行DEVELOPMENT_ENVIRONMENT都不能再与全局状态分离。这意味着您编写的代码仅适用于该应用程序的全局上下文。如果您想编写可重用的软件组件,这会妨碍您。可重用性不仅意味着第二个应用程序,它已经意味着测试和调试。或者只是您的软件的下一个版本。正如你可以想象的那样,它可以很快地以你自己的方式出现——或者说比你想要的更快。

所以这里的问题不是它本身的常量,而是更多地依赖于代码将在其中运行的单一上下文或者更好的措辞global static state。当您想在这里更好地引入更改时,您需要瞄准的目标是减少这种全局静态状态。如果您正在寻找替代方案,这一点很重要,因为它将帮助您做出更好的决定。

例如,不是在上一个代码示例中引入一组常量,而是找到您使用的地方,DEVELOPMENT_ENVIRONMENT并思考为什么将其放入其中,以及是否无法将其删除。所以首先考虑一下是否需要它(这些环境标志通常是一种气味,曾经在快速调试中需要或者因为它被认为“哦,多么实用” - 然后在数周内没有使用的代码中腐烂)。在你考虑了它是否需要它并且你到达了需要它的点之后,你需要找出为什么在那个地方需要它。它真的属于那里吗?不能 - 正如你应该对任何提供上下文的东西所做的那样 - 变成一个参数吗?

通常,根据定义,对象带有自己的上下文。如果您的记录器在开发中的行为与实际中的行为不同,则这应该是一种配置,而不是应用程序代码中某处的决定。如果你的应用程序总是有一个记录器,注入它。应用程序代码只是记录。

因此,您可以想象,这完全取决于许多不同的事情,您如何以及何时可以防止这种情况发生。我只能建议您现在就找出来,以减少整体使用量。

对于我们在应用程序中面临的常见场景,有一些实用的技巧。对于“根路径问题”,您可以将相对路径与魔术常量(如__DIR__. 例如,如果 webroot 中的前端(例如index.php)需要指向托管代码的私有应用程序目录:

<?php
/**
 * Turbo CMS - Build to race your website's needs to the win.
 *
 * Webroot Endpoint
 */
require(__DIR__ . '/../private/myapp/bootstrap.php');

然后,应用程序通常会知道它是如何工作的以及在哪里可以找到与其自身相关的文件。如果您返回一些应用程序上下文对象(并且这不能是全局的(!)),您也可以注入 webroot 文件夹:

<?php
/**
 * Turbo CMS - Build to race your website's needs to the win.
 *
 * Webroot Endpoint
 */

/* @var $turboAppContext Turbo\App\WebappContext */
$turboAppContext = require(__DIR__ . '/../private/myapp/bootstrap.php');
$turboAppContext->setWebroot(__DIR__);

现在您的网络服务器的上下文配置应用程序默认值。这实际上是一个关键部分,因为它触及了应用程序内部(但不是每个组件)内在的上下文领域。你不能阻止这种情况。就像泄漏抽象一样。您的应用程序运行在一个环境(称为“系统”)中。但即便如此,您仍希望使其尽可能独立。

就像DEVELOPMENT_ENVIRONMENT上面的常数一样,这些点对于减少和为它们找到合适的位置至关重要。也只允许一个非常特定的层来设置输入值(改变上下文)并且只有你的软件的一些高级层才能访问这些值。您的代码库的最大部分应该在没有任何这些参数的情况下工作。而且您只能通过传递参数而不使用全局来控制访问。然后在允许访问某个设置的级别上的代码(按照这个词的最佳含义),可以访问它 - 其他所有内容都没有该参数。为了获得这种安全性,您需要尽可能地杀死全局变量。

例如,重定向到另一个位置的功能需要当前请求的基本 URL。它不应该从服务器变量中获取它们,而是基于抽象访问服务器变量的请求对象,以便您可以在这里替换东西(例如,当您将应用程序移动到前端代理后面时 - 并不总是最好的例子但这可能发生)。如果您对软件进行了硬编码$_SERVER,则需要$_SERVER在软件的某些阶段进行修改。您不希望这样,而是通过使用代表您的应用程序需要的特定功能的对象来远离这个(再次)全局静态状态(这里通过超全局变量,在全局常量旁边找到那些)。

只要我们在谈论 Web 应用程序,请看一下 Symfony 的请求和响应抽象(许多其他项目也使用它,这使您的应用程序更加开放和流畅)。但这只是一个旁注。

因此,无论您想根据自己的决定做出决定,都不要被输入多少个字母所误导。当您开始考虑开发软件时需要输入的整体字母时,这样做的好处是非常短视的。

相反,要了解你在哪里引入上下文,在哪里可以阻止,在哪里不能。对于您不能的地方,请考虑将上下文作为参数而不是代码的“属性”。更流畅的代码可以让您在迁移到另一个平台时获得更多可重用代码、更好的测试和更少的麻烦。

如果您的安装基础很大,这一点尤其重要。基于这些具有全局静态状态的代码很难维护:延迟发布、爬行发布、失望的开发人员、繁重的开发。有一些教训要学习,这些教训是要了解该语言的某些特征具有哪些含义以及何时使用它们。

我能给的最好的规则——而且我根本不是一个学术开发者——是认为全球是昂贵的。它可能是建立某些东西的绝佳捷径,但是您应该知道它的价格。这个领域很广泛,因为这不仅适用于面向对象的编程,而且实际上也适用于过程代码。在面向对象编程中,存在许多提供不同方法来防止全局静态状态的教育材料,所以我什至会说那里的情况有很好的记录。但是 PHP 不是纯粹的 OOP,所以它并不总是像手头有一个对象那么容易——您可能首先需要引入一些(但是,请参阅已经可用的请求和响应抽象)。

因此,在这个问题的上下文中,我可以给出的改进您的代码的真正最佳建议是:坚持使用常量(可能使用const关键字以使它们不那么动态且更恒定),然后尝试删除它们。正如评论中已经写的那样,PHP 在跨平台文件访问方面做得非常好,只需/用作目录分隔符,这很好理解并且效果很好。尽量不要引入根路径常量 - 对于您编写的代码,这不应该是常量,而是在某个级别上的参数 - 它可以更改,例如在子请求或子应用程序中可以为您节省生命周期在重新发明轮子之前。

艰巨的任务是让事情变得简单。但这是值得的。

于 2013-05-14T09:02:52.403 回答
0

只需将一些服务器变量放入 vhost 配置并为每个选项准备不同的配置文件。使用 apache 会是(你需要 mod_env 模块):

SetEnv ENVIRONMENT dev

然后在索引中使用类似的东西:

$configFileName = getenv ('ENVIRONMENT').'.ini';

现在只需加载此文件并确定给定值的所有应用程序行为。当然,如果你使用一些框架,你可以进一步促进它,但这将是一个好的开始。

于 2013-05-13T20:32:46.473 回答
-2

您可以将常量封装在一个类中,然后通过静态方法检索它:

if(Config::devMode()) {}

echo Config::baseUrl();

这样可以节省一行和一些内存,因为您不需要实例化对象。

于 2013-05-13T20:24:30.403 回答