如何在不传递数组的情况下使数组可访问到类中?

Posted

技术标签:

【中文标题】如何在不传递数组的情况下使数组可访问到类中?【英文标题】:How can I make an array accessible into a class without passing it? 【发布时间】:2017-12-28 10:25:43 【问题描述】:

我有一个.ini 文件作为我的项目的配置。现在我想让它随处可用。 Here 是我正在尝试做的简化:

<?php

$config = [];
$config['base_url'] = '/mypath/';

class myclass

    public function myfunc()
        print_r($config);
    


$obj = new myclass;
$obj->myfunc;

正如你在小提琴中看到的,它抛出:

注意:未定义的属性:第 14 行 /in/iNZOv 中的 myclass::$myfunc

注意当我使用global 关键字时,它会抛出语法错误


看,我可以像这样将数组传递给类:

$obj = new myclass($config);

public $config;
public function __construct($config)

    $this->config = $config;

但我不能每次都对所有课程都这样做。无论如何,我想知道,是否可以使数组在全局范围内可访问?

【问题讨论】:

【参考方案1】:

使用global。您还需要$obj-&gt;myfunc(); 而不是$obj-&gt;myfunc();,因为它是成员函数

$config = [];
$config['base_url'] = '/mypath/';

class myclass

    public function myfunc()
        global $config;
        print_r($config);
    


$obj = new myclass;
$obj->myfunc();

【讨论】:

啊我明白了,所以每次我想访问$config我都必须使用global,对吧? 是的,否则它将成为局部范围变量,最终会出现未定义变量错误【参考方案2】:

myfunc 是一个方法,而不是一个属性。所以$obj-&gt;myfunc; 应该是$obj-&gt;myfunc();

虽然不推荐,但您可以在函数内部使用global 访问config

$config = [];
$config['base_url'] = '/mypath/';

class myclass

    public function myfunc()
        global $config;
        print_r($config);
    


$obj = new myclass;
$obj->myfunc();

这是why Globals are evil 的好读物。

【讨论】:

那么如果 globals 是邪恶的,有没有更好的解决方案?顺便说一句,constants 呢? @MartinAJ 是的,你可以有一个像这样的常量:define("CONFIG", "/mypath/"); 并在你的类中使用它 print_r(CONFIG); 没有任何 global 关键字。但基本上重点是,你不应该依赖来自函数/方法之外的任何东西。我相信您的第二种方法要好得多。【参考方案3】:

当您在函数外部定义变量时,它已经在全局范围内。

您也可以通过“超级全局”$_GLOBAL["variable_name"] 访问它们;

但您的问题是您将方法作为属性调用。

【讨论】:

谢谢你,你是我的第一票^_^。从 php 版本 >= 7.0 开始,您可以将数组定义为常量,因此您也可以使用它define('CONFIG', ['key' =&gt; 'value']);【参考方案4】:

最好的解决方案是使用这样的用户定义函数:

<?php

function config( $key = null )

    // $config = parse_ini_file('../out_of_root/app.ini');
    $config = [];
    $config['base_url'] = '/mypath/';

    if ( is_null($key) )
        return $config;
     else if ( array_key_exists($key, $config) ) 
        return $config[$key];
     else 
        return "key doesn't exist";
    


class myclass

    public function myfunc()
        echo config('base_url');
    


$obj = new myclass;
$obj->myfunc();

Demo

【讨论】:

只需要希望它在脚本生命周期中不会被调用1000次。那里有很多 I/O。 DI 是这类问题的答案。【参考方案5】:

不要依赖全局变量。绝不。在一个完美的世界里,你需要为你的班级写一个合适的factory。无需在需要时在任何地方输入$obj = new MyClass();,拥有工厂并创建 MyClass 实例有更好的方法。

基本上你的问题是进入依赖注入主题。一个简单的数组或对象,没关系。您的 MyClass 在这里有一个依赖项,这种依赖项将来可能会发生变化。这个问题是发明依赖注入容器背后的一个基本原因。

我会给Pimple 或Aura DI 一个熟悉容器的机会。

这是 Pimple 的示例(假设您的项目使用 composer)。转到项目根目录并获取疙瘩:

 $ composer require pimple/pimple ~3.0

在应用的早期步骤中创建和配置容器:

use Pimple\Container;

$dic = new Container();
$dic['config'] = function ($c) 
    return ['base_url' => '/mypath/'];
;

$dic['myclass'] = function ($c) 
    return new MyClass($c['config']);
;

现在您只需键入以下内容即可在应用程序中的任何位置获取您的课程:

$obj = $dic['myclass']; // $obj is a new, shiny MyClass instance here

您的 MyClass 签名应如下所示:

private $config; // Always start with reduced visibility

public function __construct(array $config)

    $this->config = $config;


public function myfunc() 
    print_r($this->config);

【讨论】:

在一个问题中突出显示,将config 作为变量传递不是一个选项,无论是作为“原样”变量还是容器的一部分。 “通过”是一个障碍。容器虽然可以静态可用,但可能会解决问题并满足要求。 我试图展示正确的方法。将配置注入(传递)到您的课程中是可行的方法。为什么注射不是一种选择?你能详细说明这背后的原因吗? @edigu 注入是许多应用程序中的一种选择和正确方法。但问题不同。有人说“但我不能每次都对所有课程都这样做。”作者不想一直传递变量($container$config)。 DI 是一种在许多情况下都有效的模式,但是在类似“Hello World”的应用程序中使用它有什么意义呢?我从不建议对简单任务使用复杂的解决方案,而 DI 是一种复杂的模式。【参考方案6】:

我也不建议使用global。容器一般都很好,但有时太多了。这是一个带有静态变量和方法的简单解决方案。

class Config

    public static $values = [
        'base_url' => '/mypath/'
    ];

    /**
     * @param string $key
     * @return null|string|int|mixed
     */
    public static function get($key)
    
        return empty(self::$values[$key]) ? null : self::$values[$key]; // alternatively you can throw an exception for a missing key.
    


class Foo

    public function printConfig()
    
        print_r(Config::$values);
    


(new Foo)->printConfig();
echo Config::get('base_url');

【讨论】:

以上是关于如何在不传递数组的情况下使数组可访问到类中?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不需要额外点击的情况下使 DataGridCheckBoxColumn 可编辑?

如何将数据库中一张表的多列映射到类中的一个数组/列表?

如何在不设置面板标题的情况下使 p:dashboard 组件可拖动

如何在不更新整个固件的情况下使嵌入式系统可配置

如何在不给定高度的情况下使内容在弹性框中可滚动?

如何在不弄乱下拉值的情况下使 Angular Reactive Formarray 中的级联下拉菜单工作