4

I have a .ini file as configuration of my project. Now I want to make it accessible everywhere. Here is a simplified of what I'm trying to do:

<?php

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

class myclass{

    public function myfunc(){
        print_r($config);
    }
}

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

As you see in the fiddle, it throws:

Notice: Undefined property: myclass::$myfunc in /in/iNZOv on line 14

Noted that when I use global keyword for it, it throws syntax error.


Look, I can pass the array to the class like this:

$obj = new myclass($config);

public $config;
public function __construct($config)
{
    $this->config = $config;
}

But I cannot do that every time for all classes. Anyway, I want to know, is it possible to make an array accessible in the global scope?

6 Answers 6

1

Working with global. Also you need $obj->myfunc(); instead of $obj->myfunc(); as it is member function

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

class myclass{

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

$obj = new myclass;
$obj->myfunc();
Sign up to request clarification or add additional context in comments.

2 Comments

Ah I see, so every time I want to access $config I have to use global, right?
yes otherwise it will become local scope variable and you will end up with undefined variable error
1

myfunc is a method, not a property. So $obj->myfunc; should be $obj->myfunc();

And though not recommended, you can use global to access config inside your function.

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

class myclass{

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

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

Here's a good read on why Globals are evil.

2 Comments

So if globals are evil, is there any better solution? btw, what about constants ?
@MartinAJ Yes, you can have a constant like this: define("CONFIG", "/mypath/"); and use it in your classes print_r(CONFIG); without any global keyword. But basically the point is, you should not rely anything coming from outside of the function/method. I believe your second approach is much more better.
1

When you define a variable outside a function it is already in the global scope.

You can access them through the "super global" $_GLOBAL["variable_name"] as well;

But your problem is that you are calling a method as a property.

1 Comment

Thank you, you are my first upvote ^_^. From php version >= 7.0 you can define arrays as constants, so you can use this as well define('CONFIG', ['key' => 'value']);
1

Don't rely on globals. Never. In a perfect world, what you need is writing a proper factory for your class. Instead of typing $obj = new MyClass(); everywhere when you need, having a factory and create MyClass instances there is far more better approach.

Basically your question is getting into the dependency injection topic. A simple array or object, it doesn't matter. Your MyClass has a dependency here and this dependency may change in the future. This problem is a basic reason behind the invention of the Dependency Injection Containers.

I would give a chance to Pimple or Aura DI to getting familiar with the containers.

Here is an example for Pimple (assuming your project uses composer). Go to project root and get pimple:

 $ composer require pimple/pimple ~3.0

Create and configure a container in early steps of your app:

use Pimple\Container;

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

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

Now you can get your class anywhere in your application by simply typing:

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

Your MyClass signature should be look like:

private $config; // Always start with reduced visibility

public function __construct(array $config)
{
    $this->config = $config;
}

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

3 Comments

It is highlighted in a question that passing config as a variable is not an option no matter as "as-is" variable or a part of a container. The "passing" is an obstacle. Container can be available statically though, what could probably solve an issue and meet the requirements.
I am trying to show the correct way. Injecting (passing) the configuration into your class is way to go. Why injection is not an option? Can you elobrate the reason behind this?
@edigu injection is an option and a correct way in many applications. But the question was different. It was said "But I cannot do that every time for all classes." An author didn't want to pass a variable all the time (either $container or $config). DI is a pattern that works in many cases, but what's the point to use it in a "Hello World"-like application? I never recommend to use complex solutions for simple tasks and DI is a complex pattern.
0

I wouldn't recommend using global either. Containers are good in general, but sometimes it's just too much. Here's a simple solution with a static variable and method.

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');

Comments

0

The best solution is using a user-defined function like this:

<?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

1 Comment

Just need to hope it's not called 1000 times in the script life cycle. A lot of I/O there. DI is the answer to this type of problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.