在我的应用程序架构中,我想用一些不会烧毁大多数开发人员眼睛的东西替换我的全局变量,因为我正在使用这样的全局变量,
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;
有更好的方法吗?
答案 0 :(得分:1)
我认为像你这样的问题一般都无法回答,但无论如何他们都应该得到答案。只是没有一个黄金法则或解决方案可以解决这个问题。
从最简单的意义上讲,我可以想象你描述的问题是应用程序运行的上下文。在人脸层面,这是多重折叠的,只需要一个不变:< / p>
define('DEVELOPMENT_ENVIRONMENT', true);
即使非常简单且易于介绍,它的价格也很高。如果它已经是您的应用程序的一部分,请首先尝试了解其含义。
你有一个应用程序代码库,在其中的某个地方 - 具体到处使用常量 - 如果此常量为TRUE
或FALSE
,则会执行代码分支。
它自己的有问题因为这样的代码往往变成复杂而难以调试。因此,无论如何(常量,变量,函数,类),您首先应 reduce 并阻止使用此类构造。
老实说,使用(全局)常数看起来也不错,特别是与替代品相比,它首先是我眼中最优选的因为它更少而且不复杂而是直截了当。您可以使用const
keyword声明它在当前PHP版本中将其转换为动态性较小的常量:
const DEVELOPMENT_ENVIRONMENT = TRUE;
这是这一小段代码的一个方面。另一个是它带来的低抽象级别。如果要为应用程序定义环境,则说开发环境为true或false是不明确的。相反,您通常有一个可以是不同类型的环境:
const ENVIRONMENT_UNSPECIFIED = 0;
const ENVIRONMENT_DEVELOPMENT = 1;
const ENVIRONMENT_STAGING = 2;
const ENVIRONMENT_LIVE = 3;
const ENVIRONMENT = ENVIRONMENT_DEVELOPMENT;
然而,这个小例子只是一个例子,可视化我的意思,使它变得模棱两可。它没有解决上面列出的一般问题和以下问题:
您可以在全局级别上为您的应用程序引入上下文。这意味着组件(函数,类)中与任何全局(此处:DEVELOPMENT_ENVIRONMENT
)相关的任何代码行都不能再与全局状态解耦。这意味着您编写的代码仅在该应用程序全局上下文中有效。如果您想编写可重用的软件组件,这会妨碍您的工作。可重用性不仅仅意味着第二个应用程序,它已经意味着在测试和调试中。或者只是软件的下一个版本。你可以想象,它可以很快地以你自己的方式站立 - 或者让你说得更快。
所以这里的问题不再是它本身的常量,而是更多地依赖于代码将运行的单个上下文或更好的措辞全局静态。当您希望在此处引入更改时,您需要瞄准的目标是减少此全局静态。如果您正在寻找替代方案,这一点非常重要,因为它可以帮助您做出更好的决策。
例如,不是在最后一个代码示例中引入一组常量,而是找到您使用DEVELOPMENT_ENVIRONMENT
的地方,并想一想为什么要将它放在那里,如果不可能将它删除。所以首先要考虑它是否需要(这些环境标志通常是一种气味,一旦需要快速调试或因为它被认为&#34;哦,多么实用&#34; - 然后代码腐烂数周无用)。在您考虑是否需要它之后,您需要找到为什么在那个地方需要它。它真的属于那里吗?可以 - 就像你应该对提供上下文的任何东西一样 - 变成一个参数吗?
通常,对象按照定义附带自己的上下文。如果您的开发人员在开发过程中的行为与实时不同,那么这应该是一个配置,而不是应用程序代码中的某个决策。如果您的应用程序始终有记录器,请将其注入。应用程序代码只记录。
你可以想象,它完全取决于许多不同的事情,你如何以及何时可以防止这种情况发生。我现在只能建议你找出,以减少整体使用情况。
我们在应用程序中遇到的常见方案有一些实用技巧。对于&#34;根路径问题&#34;您可以将 relative paths 与__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');
然后,应用程序通常会知道它是如何工作的,以及在哪里找到文件 relative 。如果你返回一些应用程序上下文对象(并且这必须不是全局的(!)),你也可以注入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__);
现在,您的Web服务器的上下文配置应用程序默认值。这实际上是一个至关重要的部分,因为它触及了应用程序内部的一个上下文区域(但不是每个组件中都是内在的)。你不能阻止这种情况。与leaking abstractions类似。有一个环境(称为&#34;系统&#34;)你的应用程序运行。但即使你想让它尽可能独立。
与上面的DEVELOPMENT_ENVIRONMENT
常数一样,这些点对于减少和找到合适的位置至关重要。此外,只允许非常特定的图层设置输入值(更改上下文),并且只允许软件的某些高级图层访问这些值。代码库的最大部分应该在没有任何这些参数的情况下工作。并且您只能通过传递参数来控制访问权限,并且只能使用全局来而不是。然后,在允许访问某个设置(在单词的最佳含义中)的级别上的代码可以访问它 - 其他所有内容都没有参数。为了获得这种安全性,您需要尽可能地杀死全局变量。
E.g。功能重定向到另一个位置需要当前请求的base-url。它不应该从服务器变量中获取它们,而是基于抽象访问服务器变量的请求对象,以便您可以在此处替换(例如,当您将应用程序移动到前端代理之后 - 并非总是最好的例子,但这可能发生)。如果您针对$_SERVER
对软件进行了硬编码,则需要在软件的某些阶段修改$_SERVER
。你并不想要它,而是通过使用代表你的应用程序所需的某个功能的对象,远离这个(再次)全局静态(这里通过超全局变量,找到你的全局常量旁边的那些)。 p>
只要我们谈论Web应用程序,请查看Symfony的请求和响应抽象(许多其他项目也会使用它,这使得您的应用程序更加开放和流畅)。但这只是一个侧面说明。
因此,无论您想做什么决定,都不要误导要输入多少个字母。当您开始考虑开发软件时需要输入的整体字母时,这样做的好处是非常短视的。
相反,要了解您在哪里引入上下文,在哪里可以预防,以及您可以在哪里。对于您不能使用的地方,请考虑将上下文设为参数而不是&#34;属性&#34;的代码。当您转移到另一个平台时,更流畅的代码可以让您获得更多可重复使用的代码,更好的测试和更少的麻烦。
如果您拥有大型安装基础,这一点尤为重要。具有全局静态的这些基础代码是一个混乱的维护:延迟发布,爬行版本,失望的开发人员,繁重的开发。有一些需要学习的课程,课程是要了解语言的某些特征以及何时使用它们的含义。
我能给予的最好的规则 - 我根本不是一个学术开发者 - 是考虑全球性的昂贵。它可以是一个极好的快捷方式来建立一些东西,但你应该知道它带来的价格。这个领域很广泛,因为这不仅适用于面向对象的编程,也适用于程序代码。在面向对象编程中,存在许多教育材料,它们提供了防止全局静态的不同方法,所以我甚至会说那里的情况有很好的记录。但PHP并不是纯粹的OOP,因此手头有一个对象并不总是那么容易 - 你可能首先需要介绍一些(但是,同时也要看一下已有的请求和响应抽象)。
因此,在这个问题的上下文中,我可以给出的改进代码的真正最好的建议是:坚持常数(可能使用const
关键字使它们不那么动态且更加恒定)和然后尝试删除它们。正如已经在评论中写的那样,PHP在跨平台文件访问方面做得非常好,只需使用/
作为目录分隔符,这很好理解并且工作得很好。尽量不要引入根路径常量 - 这对于你编写的代码不应该是常量,而是某个级别的参数 - 它可以改变,例如在子请求或子应用程序中可以为你节省生命在重新发明轮子之前。
艰巨的任务是保持简单。但它值得。
答案 1 :(得分:0)
只需将一些服务器变量放入vhost配置中,并为每个选项准备不同的配置文件。使用apache就可以了(你需要mod_env模块):
SetEnv ENVIRONMENT dev
然后在索引中使用类似的东西:
$configFileName = getenv ('ENVIRONMENT').'.ini';
现在只需加载此文件并确定给定值的所有应用程序行为。当然,如果你使用一些框架,你可以进一步促进它,但这将是一个良好的开端。
答案 2 :(得分:-2)
您可以将常量封装在一个类中,然后通过静态方法检索它:
if(Config::devMode()) {}
echo Config::baseUrl();
这样就可以保存一行和一些内存,因为你不需要实例化一个对象。