Php 使环境变量全球化是一种良好的做法吗?

Php 使环境变量全球化是一种良好的做法吗?,php,Php,我有一些模块化(对象和类)JavaScript和PHP。我不断得到建议,要去掉全局变量…“它们很糟糕”…我想是因为它们会导致依赖关系 然而,我应该把环境变量放在哪里——最好的例子是路径信息 这是一个典型的例子 下面的UploadFile类需要 const PICTURES = '../pictures/'; 特别是在这一点上(无需阅读整个课程) 不允许将文件上载到任何位置。我更愿意把它放在一个GlobalClass中,然后从那里访问它。这是有意义的,因为其他代码需要知道图片的去向,而我

我有一些模块化(对象和类)JavaScript和PHP。我不断得到建议,要去掉全局变量…“它们很糟糕”…我想是因为它们会导致依赖关系

然而,我应该把环境变量放在哪里——最好的例子是路径信息

这是一个典型的例子

下面的UploadFile类需要

const     PICTURES = '../pictures/';
特别是在这一点上(无需阅读整个课程)

不允许将文件上载到任何位置。我更愿意把它放在一个GlobalClass中,然后从那里访问它。这是有意义的,因为其他代码需要知道图片的去向,而我只有一个位置可以进行更新

环境变量可以作为全局变量使用,这样就可以从多个模块中访问它们,并且只在一个地方进行编辑

<?php

/**
 *      Module  :       Model
 *      Name    :       UploadFile
 *      Input   :       File Information
 *      Output  :       Resized Files in .jpg format
 *      Notes   :

 resizeMove() - resizes the picture to $maxMedium and $maxSmall and moves the file to a permanent location.  
 makeDimensions() - calculates the dimensions of the new images so that there is not distortion if possible.
 getImage() - creates a php image for manipulation.
 updateSessionAndDb - updates the mysql table - move out.

 */

    class UploadedFile
    {
    const     PICTURES = '../pictures/';

    private  $originalWidth, 
             $originalHeight, 
             $newWidth, 
             $newHeight, 
             $maxMedium = 50,
             $maxSmall = 20;

    private  $src = NULL;

    private 
             $fileType,
             $fileName,
             $sessionId,
             $path_medium,
             $path_small;

    function __construct($fileType, $fileName)
    {
        $this->sessionId = Session::get('id');
        $this->path_medium = UploadedFile::PICTURES . "$this->sessionId.jpg";
        $this->path_small = UploadedFile::PICTURES . "$this->sessionId-1.jpg";
        $this->fileType = $fileType;
        $this->fileName = $fileName;
    }

    public function createImages()
    {
        if(move_uploaded_file($this->fileName, $this->path_medium))
        {
            if($this->getImage($this->path_medium))
            {
                list($this->originalWidth,$this->originalHeight)=getimagesize($this->path_medium);
                $this->resizeMove($this->maxMedium,$this->path_medium);
                $this->resizeMove($this->maxSmall,$this->path_small);
                imagedestroy($this->src);
            }
        }
    }

    private function resizeMove($max, $path)
    {
        $this->makeDimensions($max);
        $image_true_color = imagecreatetruecolor($this->newWidth, $this->newHeight);
        imagecopyresampled($image_true_color, $this->src, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->
        originalWidth, $this->originalHeight);
        imagejpeg($image_true_color, $path);
        imagedestroy($image_true_color);
    }

    private function makeDimensions($max)
    {
        $this->newWidth=$this->originalWidth; 
        $this->newHeight=$this->originalHeight;
        if(($this->originalWidth > $this->originalHeight) && ($this->originalWidth > $max))
        {
            $this->newWidth = $max;
            $this->newHeight = ($max / $this->originalWidth) * $this->originalHeight;
        }
        elseif($this->originalHeight > $this->originalWidth && $this->originalHeight > $max)
        {
            $this->newHeight = $max;
            $this->newWidth = ($max / $this->originalHeight) * $this->originalWidth;
        } 
        elseif ($this->originalWidth > $max)
        {
            $this->newWidth = $this->newHeight = $max;
        }
    }

    private function getImage($path)
    {
        $type_creators = array( 
            'image/gif' => 'imagecreatefromgif', 
            'image/pjpeg' => 'imagecreatefromjpeg', 
            'image/jpeg' => 'imagecreatefromjpeg', 
            'image/png' => 'imagecreatefrompng'); 
        if(array_key_exists($this->fileType, $type_creators)) 
        { 
            $this->src = $type_creators[$this->fileType]($path); 
            return true; 
        }
    return false; 
    }
}
修改对象生成器示例

    class ObjectMaker
    {
        public function makeSignUp()
        {
            $DatabaseObject = new Database();
            $TextObject = new Text();
            $MessageObject = new Message();

            return new ControlSignUp( $DatabaseObject, $TextObject, $MessageObject );        
        }
注意事项:


我可能有类似于SignUp的类,所以我可以使用继承来减少对象创建的冗余,通过使用ObjectMaker类-回到最初的问题-我可以在这个“模式”中包括全局对象的注入,而不仅仅是对象。

可能不会。您可以创建一个路径获取程序,它输出路径类的属性(即
path::pictures

然后,在这个级别上,这取决于开发人员


我认为,为了公司的利益,最好将它们都放在一个名称空间中,并以这种方式调用它们。当新开发人员出现时,它会有所帮助。

常量没有全局变量那么糟糕,将其用于path是迄今为止克服PHP没有“真”根路径变量的尴尬的最常用方法(您可以使用DIR基于当前脚本,但不能基于调用当前脚本的脚本)

全局变量不好的主要原因不是因为它们是全局变量,而是因为它们可以在脚本中的任何位置更改。事实上,这是我对PHP的主要抱怨之一-$\服务器变量可以在脚本运行期间更改,我希望它们是常量

只能定义和使用常量,无法对其进行编辑。只要您能够很好地记录全局变量的存在,那么管理它们并不比管理任何其他PHP环境变量更困难


只要你不跟他们一起发疯就好了。请记住,在进行测试时,环境总是扮演着一个角色,只要您了解环境并可以轻松地模拟它,那么它就不会给测试带来更多问题。

如果您想使类可重用,您不应该在其中硬编码,而应该将其注入。例如会话id和映像的基本目录。将这些作为参数添加到构造函数中:

function __construct($fileType, $fileName, $sessionId, $prefixPictures)
{
    $this->fileType = $fileType;
    $this->fileName = $fileName;
    $this->sessionId = $sessionId;
    $this->prefixPictures = $prefixPictures;

    $this->path_medium = $prefixPictures . $this->sessionId . ".jpg";
    $this->path_small = $prefixPictures . $this->sessionId . "-1.jpg";
}

此外,您应该创建自己的类,一个用于调整图片大小,另一个用于进行大小计算。实际上,这样的类已经存在,所以您只需要包含一些文件,并调整大小(例如使用)。

全局变量的问题在于,它使您的类依赖于它的存在,从而默认情况下破坏了类。如果它是一个库类,那么这一点很重要,但如果它专用于您的应用程序,那么这一点就不那么重要了——但它始终是一个很好的目标。此外,如果它是一个
const
define
,那么它在执行过程中就不能被更改(这种情况的发生频率可能比人们想象的要高,即使是在您的示例中,例如在单元测试中)。最优雅的解决方案是采用依赖注入模式,虽然有时设置该类的成本超过了减少依赖项的好处。是的……如果我设置了一个具有私有成员的全局类并通过getter进行访问……那么我可以使用依赖项注入来注入该类……最佳实践与大量工作相比……hmmmmIf
UploadedFile
的唯一配置项是根路径,我会将
$picturesRoot
添加到构造函数中,或者可能会将setter
setPicturesRoot($picturesRoot)
添加到类中。这样,这个类就不必担心接受特定于应用程序的配置对象——你的控制器可以做这些事情。@halfr-同意,下面的hakre也同意。这样,我就可以在一个位置更新它们,使它们成为私有的,但是访问任何地方。这听起来像是最佳实践。我已经看到了很多…通过构造函数进行依赖注入…这比创建一个处理DI的ObjectMaker(我目前的做法)要简单一些。实际上我需要更新该文件以通过构造函数…更简洁一些。这是会话方面的一个好地方,另一种依赖。然而,我可能倾向于使用更多的setter——虽然对象需要所有这些变量,但我目前在某种程度上同意Clean Code的格言,即三个以上的参数变得非常笨拙。但是,+1还是一样。@halfer:如前所述,该类做的太多了,
$fileType
$fileName
看起来多余,实际上只是为了标识一个图像。@Allfoo您所做的不是DI容器就是抽象工厂。需要注意的是,DI(依赖项注入)在没有DI容器或抽象工厂的大多数项目中都很有用。全局变量(包括常量)的最大问题是它们创建了一个难以控制的依赖项列表。如果您构建了一个接受注入设置的类,那么可以轻松地单独测试该类。与依赖全局变量和/或常量的类(类常量更好,但请注意,它们在配置时使用有限)相比,它们不容易注入,但必须在运行测试之前进行设置。这正是我所说的wilmoore。但由于软件已经依赖于环境(PHP版本引入了某些在其他版本上不可用的服务器变量,Apache和Nginx也引入了不同的变量),如果您有一个框架或更大的系统
    class ObjectMaker
    {
        public function makeSignUp()
        {
            $DatabaseObject = new Database();
            $TextObject = new Text();
            $MessageObject = new Message();

            return new ControlSignUp( $DatabaseObject, $TextObject, $MessageObject );        
        }
function __construct($fileType, $fileName, $sessionId, $prefixPictures)
{
    $this->fileType = $fileType;
    $this->fileName = $fileName;
    $this->sessionId = $sessionId;
    $this->prefixPictures = $prefixPictures;

    $this->path_medium = $prefixPictures . $this->sessionId . ".jpg";
    $this->path_small = $prefixPictures . $this->sessionId . "-1.jpg";
}