Accessing a global variable inside nested functions - php

Here's my scenario:
$foo = bar;
one()
{
two()
{
three()
{
// need access to $foo here
}
}
}
I know I could pass $foo down all three functions, but that isn't really ideal, because you may or may not require it, besides, there are other parameters already and I don't want to add to that list if I can prevent it. It's only when you get to three() do you need $foo. I know I could also specify global $foo; in three(), but I read that this wasn't a good practice.
Is there another way $foo can be made available to three() without doing either of those?
To provide a little more info, $foo in this case is info on how to connect to the database e.g. server, user, pass, but only in three() does it actually need that info. Of course I could connect to the database right as the document loads, but that feels unecessary if the document might not need it.
Any ideas?
UPDATE: I'm sorry, I didn't mean to have "function" at the beginning of each function implying that I was created them in a nested way.

Yes, you can use global, or pass it through as a parameter. Both are fair ways. However, I'd do the latter. Or, you can also use closures and the use keyword:
$foo = 'bar';
$one = function() use($foo) {
$two = function() use($foo) {
$three = function () use($foo) {
// access to $foo here
};
};
};
Can also be use(&$foo) if you need to modify the top $foo's value inside of $three()

Using global is not a bad practice if used properly. This case you would use global and it will be totally fine.
Since global makes functions get access to global variables, there are data corruption risks.
Just make sure to use with caution and you know what you're doing (i.e. not accidentally change the data that you don't want it to change. This sometimes causes some nasty bugs that's hard to track.)
Summarize: global in this case is perfectly fine.
What's really bad is nested functions, at least in PHP.

Don't listen anybody, who are speaking about global.
Read books about OOP (e.g. this one), read about Dependency Injection, Factory-patterns.
Dependency Injection is the best way to create flexible and easy-to-maintain code, and by DI philosophy you will pass $foo from first to third function in arguments, or will pass Context object with all necessary variables (if you want to minimize count of arguments).
More about DI you can read here: http://components.symfony-project.org/dependency-injection/trunk/book/00-Introduction

Related

Are static functions any better than globals? [duplicate]

I'm creating a basic framework in PHP. I need to pass data for the current page into different functions, allow them to modify and save it, and then pass it back to the page to be displayed. I was originally planning on storing the data in a global variable like $GLOBALS['data'], but I'm starting to think that using a global is a bad idea. So I'm thinking that instead I will put a static variable in the system class, and access it using system::$data. So, my question is, which would be better and why?
This:
$GLOBALS['data'] = array();
$GLOBALS['data']['page_title'] = 'Home';
echo $GLOBALS['data']['page_title'];
Or this:
class system
{
public static $data = array()
}
function data($new_var)
{
system::$data = array_merge(system::$data, $new_var);
}
data(array('page_title' => 'Home'));
echo system::$data['page_title'];
There really is no difference between a global variable and a public static variable. The class variable is namespaced a tiny bit better, but that hardly makes any difference. Both are accessible anywhere at any time and both are global state.
As it happens, I just wrote an exhaustive article on the subject:
How Not To Kill Your Testability Using Statics
So, my question is, which would be better and why?
You already sense that there is some problem putting this all into globals. Although you have developed some thoughts to encapsulate things into a class.
I think that is a good starting point. Let's add some more spice to the cooking to get this more fluent at the beginning:
$data = new ArrayObject(array());
$data['page_title'] = 'Home';
You have created an object now that you can pass along containing your data. Just pass $data to the area's where it's needed. No global or global static variable needed.
You can even make that type more concrete later on by extending from ArrayObject with your own type.
For the record.
Pro of static:
Clarity of the code. For example:
function fn() {
System::data()
}
versus
function fn() {
global $system;
$system->data()
}
Cons of static:
If you are using psr-4 then you must add (and include) a new class (and a new file). It impacts the performance even if you use opcache (opcache aleviates it but it's not magic).
You must define a block of code.

Is it possible to declare a variable as "always global"?

Is there any way I can define a variable such a way that I don't need to global $var1; in every function? Just define it in beginning and keep using where ever needed. I know $GLOBALS exist, but don't want to use it.
First let me try to explain why you shouldn't use globals because they are extremely hard to manage. Say a team member overrides an $ADMIN variable in a file to be 1, and then all code that references the $ADMIN variable will now have the value of 1.
globals are so PHP4, so you need to pick a better design pattern, especially if this is new code.
A way to do this without using the ugly global paradigm is to use a class container. This might be known as a "registry" to some people.
class Container {
public static $setting = "foo";
}
echo Container::$setting;
This makes it more clear where this variable is located, however it has the weakness of not being able to dynamically set properties, because in PHP you cannot do that statically.
If you don't mind creating an object, and setting dynamic variables that way, it would work.
You need to pass the variable as a parameter to that function to avoid using GLOBALS.
The Problematic Scenario (Works ! but avoid it at all costs)
<?php
$test = 1;
function test()
{
global $test;
echo $test; // <--- Prints 1
}
test();
The right way...
<?php
$test = 1;
function test($test)
{
echo $test; // <--- Prints 1
}
test($test); //<--- Pass the $test param here
This behaviour called as superglobal variable. But php has limited predefined list of them: Superglobals.
So you cannot add your own superglobal variable.
Variable scope
My suggestions from the most to less radical:
Edit source code of PHP and add your own superglobals.
Do not write code at all.
Do not use PHP (use different language with different variable scope policy).
Do not use functions (write plain script).
Use constants instead of variables.
Use function params instead of using globals.
Use static variables instead of globals. (\G::$variable)

Can i change the value of local variable sitting inside the function in PHP?

I was reading an article about Data Encapsulation in PHP, and the author explained in such a way that it made me to wonder if this is really possible? here is what he said.
The primary purpose of encapsulation
(scope) is to ensure that you write
code that can't be broken. This
applies to scope in general, so let me
use a simpler example of a local
variable inside a function:
function xyz ($x) {
$y = 1;
while ($y <= 10) {
$array[] = $y * $x;
$y++;
}
return $array;
}
The purpose of this function is to
pass a number and return an array. The
example code is pretty basic. In order
for function xyz() to be dependable,
you need to be guaranteed that it does
the exact same thing every time. So
what if someone had the ability to
from the outside change that initial
value of $y or $array? Or even $x? If
you were able to do that from outside
of the function, you could no longer
guarantee what that function is
returning.
Now this made me wonder can i really change the value of local variable sitting inside the function without using any argument as demonstrated above ?? if it is possible how do i do it?
thank you..
For this example you wouldn't be able to change any of the variables, because they're all declared inside of the function.
But if you had a class with a public class variable, you could change that outside of the class if you wanted to. (That's bad form and might screw a lot of things up, though.)
Unless you add a magic setter method ( __set($key,$value) ), and configure it in such a way that you can access that internal member, then no. You can change the key when you make the function if you're using some form of factory, but if you haven't made it public, there's no other way.
The only visible exception would be with a singleton factory: you could make a new instance of your singleton method with different parameters (changing it everywhere else), but I doubt you'd be likely to do that with a method.

What is the point of having $this and self:: in PHP?

Why does PHP require you to explicitly write $this? I would understand if you had to use $this here:
function foo($bar) {
$this->bar = $bar;
}
But you must write it explicitly in verbose code that looks like this:
$this->var3 = globalFun($this->var, $this->var2[$this->anotherVar], $this->method());
as opposed to:
$var3 = globaFun($var, $var2[$anotherVar], method());
So what is the point of $this?
Additional Bonus Question:
Why do we have to differentiate static references and instances? Why do we need:
static function getValue() {
return self::value;
}
Can't PHP find out at runtime if the variable/method in question is static? Now if I want to change a method from static to non-static, I have to replace all those self:: with $this-> (and vice-versa).
Wouldn't it be better if we had a $this that behaves like it does in Java?
Since this was re-opened, I'll post here my answer, as promised.
TL;DR version If it were not required to qualify a member access, there would be not only performance penalties, but the same line of code could simultaneously signify a field access and a local variable access, depending on the code path.
Full version
In PHP, there's always one symbol table active at the table. This is either the global symbol table or a function/method local symbol table (which by the way, are lazily built). Superglobals and optimizations like compiled variables aside, when a variable $var is requested, it is looked up in the current symbol table. Since the object properties live not on the symbol tables, but instead on either in the objects (the instance properties) or the structure associated the class (the static properties), a lookup for $var can never return a property.
To bring a given variable to the function scope, you must explicitly signal your intention by creating a reference. Examples:
$myglobal = 7;
class A {
private $prop;
public function meth() {
global $myglobal; //bring a global to the current scope
$prop =& $this->prop; //brings a property to the current scope
$local = 4;
$lambda = function () use (&$local) { };
}
}
Obviously, this is just a more sophisticated way to phrase what currently happens. The question is why this behavior?
After all, in Java we only have to type this.prop when there's a local variable called prop hiding the property. Why is this not a good option for PHP?
I can think of several reasons.
The object properties are determined at runtime
PHP has something called "dynamic properties". You can assign new properties to objects at runtime. In fact given two objects of the same class, one can have a given property $a and while the other doesn't. Example:
$obj1 = new stdClass();
$obj2 = new stdClass();
$obj1->a = 7;
In PHP, the defined local variables are determined at runtime
Variables do not have to be declared; consequently, depending on the code path, at some point a variable may or may not be defined. To add insult to the injury, we also have the monster called "variable variables". Example:
class A {
private $g = 3;
public function func($varname) {
if (rand(1,2) == 1) {
$g = 4; //no block scope; the scope is the function's
}
$$varname = 5; //god knows what's happening here
//if local variables hid properties, we'd have trouble
}
}
In Java, a given identifier may also represent, inside the same function, a local variable and a property, but:
Not within the same block (in PHP, all blocks in a function share exactly the same scope).
You get a warning if you're hiding a property.
Crucially, in any given occurrence of an identifier, it's either a property or a local variable, it can't sometimes be one and other times the other.
Consequences
Owing to these facts, it would be impossible to determine at compile time if $var referred to a local variable or to a property. Consequently:
At runtime, every time a variable occurred, it would have to looked up first in the local symbol table, then in the instance properties table, and finally in the static properties list, or any other order (since there can't be an instance and a static property with the same name and static properties need to be declared, there would be some optimization potential here, but the point stands). This means a symbol would have, in the worst case, would have to be looked up in three different places. This is bad from a performance perspective.
A given symbol occurrence could mean different things on different occasions. This is a recipe for disaster.
Okay, so let's remove the need for writing $this everywhere. Take a look at this situation:
class Foo {
public function setBar($value) {
$bar = $value;
}
}
$foo = new Foo();
$foo->setBar('some value');
Is $bar a local variable or a member of $foo?
There has to be some differentiation. They could have allowed declaration of local variables with the var keyword, but that would not have been backwards-compatible and would have been very confusing to people upgrading from older versions of PHP.
Same thing applies to self::. How does the interpreter know whether the function you wanted to call is global or specific to the class?
PHP was not OOP.
Now it is, but with side effects.
Actually, I know people who use this. in Java even where unnecessary because they feel it creates clearer code ;) I don't have a really definite answer, but I guess that, internally, getting $var would always have to be translated to $this->var. So it's not like someone intentionally made things more complicated by forcing us to do $this->var, but just decided to not implement the $var shortcut. If that helps in any way, I don't know ;)

Push a variable into global scope?

We use instantiate and put system critical objects in $GLOBALS for easy access from anywhere (e.g. DB, Cache, User, etc.).
We use $GLOBALS so much that it would (yes, really) drop the amount of code quite a bit if I could reference it like $G = &$GLOBALS for a shorthand call.
The problem is that, per my experience and several hours of Googling, I have not found any construct in PHP which allows you to 'flag' a var as global, making $GLOBALS first class, and everything else second class.
Am I missing something? Is this possible?
<?php
function &G($name) {
if(func_num_args() > 1) {
$GLOBALS[$name] = func_get_arg(1);
}
return $GLOBALS[$name];
}
G('test', 'hey');
echo G('test'); // outputs hey
echo $test; // outputs hey
$b =& G('test');
$b = 'hello';
echo G('test'); // outputs hello
echo $test; // outputs hello
Instead of putting everything into $GLOBALS you might want to take a look into the registry concept that is widespread in the php world.
However, having many global variables/objects is a sign of bad design and high coupling. Using something like $G guarantees spaghetti code and a soon-to-come maintenance nightmare. Who cares if you can drop the amount of code by a few characters?
No, but you can use a little trick. Create a global function by the same name as your global var, and have it return the global instance. Eg.:
function db() {
return $GLOBALS['db'];
}
You can now write your code as:
...
$stuffs = db()->query("select * from stuff");
...
You may recognise this as a variant over the singleton pattern, but a syntactically much more pleasant one.
Others have mentioned it, but you should also consider not using global objects in the first place. I generally prefer to pass objects in to there where it's needed (dependency injection). I'm not overly found of the registry pattern though.
global $variable; //?
In addition to the registry concept Middus points out, there are several approaches and concepts around this, some of which you can find in the answers to this question:
In a PHP project, how do you organize and access your helper objects?

Categories