Unable to access global variable in included file - php

I am having an unexpected issue with scope. The include documentation (also applies to require_once) says the required file should have access to all variable at the line it was required.
For some reason I am not able to access a class instantiated with global scope inside a function that was required in.
Would anyone know why? I am obviously missing something.
I got it working through a reference to $GLOBALS[], but I still want to know why it is not working.
UPDATE:
The error I am getting is:
Fatal error: Call to a member function isAdmin() on a non-object in <path>.php on <line>
Code:
$newClass = new myClass();
require_once("path to my file");
----- inside required file -----
function someFunction() {
$newClass->someMethod(); // gives fatal error. (see above).
}

Functions define a new scope, so inside a function you cannot access variables in the global scope.
Variable Scope
within user-defined functions a local
function scope is introduced. Any
variable used inside a function is by
default limited to the local function
scope
About included files, the manual states:
When a file is included, the code it
contains inherits the variable scope
of the line on which the include
occurs.
So if you include something in a function, the included file's scope will be that of the function's.
UPDATE: Looking at your code example edited into the question, global $newClass; as the first line of the function should make it working.
$newClass = new myClass();
require_once("path to my file");
----- inside required file -----
function someFunction() {
global $newClass;
$newClass->someMethod();
}
Be aware though that using global can quickly make your code more difficult to maintain. Don't rely on the global scope, you can pass the object to the function as a parameter, or use a Singleton/Registry class (some tend to argue against the latter, but depending on the case it can be a cleaner solution).

The included code doesn't have a scope different than the code surrounding it. For example:
function a() {
echo $b;
}
This will fail even if echo $b is in an included file. If you replace the above with:
function a() {
include 'file.php';
}
... and file.php contains:
echo $b;
... then it's the same thing as if you wrote:
function a() {
echo $b;
}
Think of it this way: whenever you use include / require, the contents of the included file is going to replace the include / require statement, just as if you removed the statement and pasted the contents of the file in its place.
It doesn't do anything else as far as scope is concerned.

Related

PHP - Accessing variables in an included script from an included script

I have a list of files that I require_once at the beginning of my main scripts.
In one of those files, I have a bunch of functions.
In another one of those files, I have a bunch of constants (which are variables at the moment, but they are essentially constants).
Main.php
require_once \Constants.php
require_once \Functions.php
From within main.php, I am able to call functions and call the constants from their respective scripts... I am also able to call functions and pass the constants from Constants.php as parameters to the functions.
However, I am not able to use functions that have the constants embedded within them.
In other words, I cannot use the functions from Functions.php that already have the variables from the Constants.php file within the functions, but I am able to use functions from Functions.php if they do not have any variables from other included files within the function.
Function FirstFunction(){ echo $Constant1; return 1 }
FirstFunction() uses $Constant1 from Constants.php and does not work.
Function SecondFunction($param){ echo $param; return 1 }
SecondFunction() can be passed $Constant1 from Constants.php as a parameter and it works fine.
Questions:
Is there a way for me be able to use my Main.php to call a function file and a constant file and have the function file use variables from the constant file without explicitly calling or passing them from within Main.php?
If I were to daisy chain them (Main.php calls Functions.php; Functions.php calls Constants.php) will this work? (I kind of tried this but not well enough to either trust or rule out this method just yet).
Note
Most of the information I am able to find is regarding using variables from included files, but not specifically about included files using variables from other included files.
This sounds like a simple scope issue, that has nothing to do with your include-cycle.
When you create your 'constants' as normal PHP-variables ($name='value';), in the root scope of the Constants.php, then they must be called inside any later functions, by referencing them first ... like this:
$name='value';
/** other stuff **/
function Foo(){
global $name;
//You have access to $name here
}
The true solution tho, is to actually define your constants as real constants, which makes them available in any scope ... like this:
define('NAME','value');
/** other stuff **/
function Foo(){
//You immediately have access to NAME here
}
Only downside to true constants is, that they are constant ... meaning, they can’t be changed at a later point in your script.
You can read more about 'scope' here: http://php.net/manual/en/language.variables.scope.php
include() works as if the contents of the file being included are literally cut/paste into the spot where the include() call is:
variables.php:
<?php
$foo = 'bar';
test.php:
<?php
var_dump($foo); // notice: undefined variable
include('variables.php');
var_dump($foo); // string(3) "bar"
Note that standard PHP variable scoping rules apply. So if you do the include() inside a function:
<?php
var_dump($foo); // notice: undefined variable
function test() {
var_dump($foo); // notice: undefined variable
include('variables.php');
var_dump($foo); // string(3) "bar"
}
test(); // call the test function
var_dump($foo); // notice: undefined variable
notice how $foo doesn't exist before/after the function is defined/called - it will only exist WITHIN the function, and only AFTER it's been included().
If you want your standard variables to be truly global, you'll have to include the file at a global scope, or declare them global:
variables.php:
<?php
global $foo;
$foo = 'bar';
and then using the same script, $foo will "magically" appear for the final var_dump, because it's been made global.

Variable accessibility with require_once/ob_start()

Maybe I'm just tired or just am simply confused, but I'm having a strange issue dealing with some require_once() calls and ob_start().
Basic Structure:
Top of Main.php:
require_once 'config.php'; // includes variable $A = "bar", and Function "foo"
function getPage(){
ob_start();
include 'some_file.php';
$html = ob_get_clean();
echo $html;
die();
}
getPage();
some_file.php
require_once 'config.php'; // includes same config file
var_dump($A); // NULL
foo(); // runs, returns correct value
Config.php
$A = 'bar';
function foo(){
return "FOO";
}
So, what is wrong here? I'm including a file while buffering output. The required file config.php holds a variable and function. When including some_file.php during the buffer, the variable $A is apparently NOT set/accessible. The function foo CAN execute.
The documentation says:
When a file is included, the code it contains inherits the variable
scope of the line on which the include occurs. Any variables available
at that line in the calling file will be available within the called
file, from that point forward. However, all functions and classes
defined in the included file have the global scope.
Your provided code does not illustrate the problem that you're describing. When I run it as-is, it correctly shows that the variable is defined.
That being said, the thing to remember is that what looks like a global variable in an included file actually ends up in the scope of the function that's calling it. So if the first time require_once() is called is from a function, the $A variable is scoped to the function - and disappears when the function returns, just like any other variable defined inside the function.
If you absolutely must define a global variable inside an included file (are you sure? really?), make sure you only include that file from the global scope - not from within a function. If you need to access the variable from within a function, include the file outside the function, and then use the global keyword to access the variable from within the function.

PHP Accessing function in global scope from a class method

I have the following simple code:
$a = 'hello';
function myfunc() {
echo 'in myfunc';
}
class myclass {
function __construct() {
myfunc();
echo $a;
}
}
$m1 = new myclass();
The echo $a within the method gives an error as you would expect since $a is in the global scope and cannot be accessed from within the class without first declaring it as global. That is documented in the PHP manual.
The call to myfunc() does work and I don't understand why. It is also declared in the global scope but the method can access it without first declaring it as global. I can't seem to find anything in the PHP manual that explains why this works.
Maybe I've been doing PHP for too long and this is something so simple I've forgotten how it works. Any insight or a link to where in the PHP manual it says you can access a global function from within a class method would be appreciated.
thanks in advance.
Functions aren't scoped (except if you use namespaces). Only methods are in classes and variables everywhere.
It's supposed to work; everything is correct: you can call functions, once defined, from everywhere.
I'm not sure if this is a new thing for namespaces...
http://www.php.net/manual/en/language.namespaces.fallback.php
Blockquote
For functions and constants, PHP will fall back to global functions or constants if a namespaced function or constant does not exist.

PHP Variable Scope Issue

In my code, I use a public load_snippet function of a class when I need to include HTML or PHP snippets. (I do this instead of a direct include_once because the directory structure varies depending on certain variables).
I had some issues with variable scopes, so I've narrowed down the problem to this: let's say I define a variable within my page:
$variable = 'Hello World!";
Then, I need load in a snippet:
$APP->load_snippet("slider");
The snippet renders perfectly, except that PHP gives an undefined variable error if I try to reference $variable in the slider code. If I directly include the php file, it works as expected, so I don't understand why I'm having this problem, since this is the load_snippet function:
public function load_snippet($snippet){
if(file_exists("app/".$this->APP_TYPE."/snippets/".$snippet.".php")){
include "app/".$this->APP_TYPE."/snippets/".$snippet.".php";
}
else{
include 'common/txt/404.txt';
}
}
Any help you can give me is much appreciated.
The file is being included within the context of the load_snippet() function, and therefore has only those variables which exist within that function. One way to modify this is to make your function accept two variables: the filename and an array of values.
public function load_snippet($snippet, $content) {
if (is_array($content)) extract($content);
if (file_exists("app/".$this->APP_TYPE."/snippets/".$snippet.".php")) {
include "app/".$this->APP_TYPE."/snippets/".$snippet.".php";
} else {
include 'common/txt/404.txt';
}
}
Then
$arr = array('variable' => 'Hello world!');
load_snippet('slider', $arr);
I think include inside a function makes no sense to me... I think that you should put in function
global $variable;
Note that include will put the code inside the function(include will be replaced by code) as i know..
The way you are doing it is an ugly one, but you can use global $variable inside the snipped to refer to the variable. However if you include the snipped inside a function or a method, you'll have to make the variables in that function/method global as well
If you need $variable inside of the App::load_snippet() method, it would probably be best to pass it in:
public function load_snippet($snippet, $var='Hello world'){
if(file_exists("app/".$this->APP_TYPE."/snippets/".$snippet.".php")){
include "app/".$this->APP_TYPE."/snippets/".$snippet.".php";
}else{
include 'common/txt/404.txt';
}
}
//do something with $var
}
You can set a default for when $variable hasn't been set. No globals, no out of scope variables.
Instead you can use the constants like define('VARIALABLE','value'). which will be available to you anywhere in your file
You are including inside a class. Which means that the included file has the same variable scope as the line of code which includes it has. TO fix this all you need to do is put
global $variable;
Above the include.

Function scopes in regards with includes in PHP

I'm having a bit of trouble understanding includes and function scopes in PHP, and a bit of Googling hasn't provided successful results. But here is the problem:
This does not work:
function include_a(){
// Just imagine some complicated code
if(isset($_SESSION['language'])){
include 'left_side2.php';
} else {
include 'left_side.php';
}
// More complicated code to determine which file to include
}
function b() {
include_a();
print_r($lang); // Will say that $lang is undefined
}
So essentially, there is an array called $lang in left_side.php and left_side2.php. I want to access it inside b(), but the code setup above will say that $lang is undefined. However, when I copy and paste the exact code in include_a() at the very beginning of b(), it will work fine. But as you can imagine, I do not wish to copy and paste the code in every function that I need it.
How can I alleviate this scope issue and what am I doing wrong?
If the array $lang gets defined inside the include_a() function, it is scoped to that function only, even if that function is called inside b(). To access $lang inside b() you need to call it globally.
This happens because you include 'left_side2.php'; inside the include_a() function. If there are several variables defined inside the includes and you want them to be at global scope, then you will need to define them as such.
Inside the left_side.php, define them as:
$GLOBALS['lang'] = whatever...;
Then in the function that calls them, try this:
function b() {
include_a();
print_r($GLOBALS['lang']); // Now $lang should be known.
}
It is considered 'bad practice' to use globals where you don't have to (not a consideration I subscribe to, but generally accepted). The better practice is to pass by reference by adding an ampersand in front of the passed variable so you can edit the value.
So inside left_side or left_side2 you would have:
b($lang);
and b would be:
function b(&$lang){...}
For further definitions on variable scopes check this out

Categories