Scope loss in included files in php - php

There are a few posts relevant to this but I'm not seeing anything near to the situation I'm struggling with.
I've inherited a rather large codebase which the original designer has taken some interesting methods of design. I'm attempting to call a method of a class that's defined. The class file itself has some global variables set. I call this method from a function, where also, I've included this file. When the method runs, the global variables are no longer defined. See below:
My File:
<?php //myScript.php
echo("Calling foo(): ");
foo();
function foo() {
include '../../php/class.bar.php';
$bar = new bar();
$bar->doSomething();
}
?>
../../php/class.bar.php:
$GLOBAL_ARRAY_ONE[0] = 'Here I am';
$GLOBAL_ARRAY_ONE[1] = 'JT';
class bar {
public $itsFoo = array();
public $itsBar = array();
public function doSomething() {
global $GLOBAL_ARRAY_ONE;
$this->itsFoo[0] = $GLOBAL_ARRAY_ONE[0];
$this->itsFoo[1] = $GLOBAL_ARRAY_ONE[1];
var_dump($this->itsFoo);
}
}
So, when I run "myScript.php" The output is: calling foo(): NULL
I personally wouldn't declare global arrays in a script like that but, I see no reason why I shouldn't have access to them.
Any ideas? Thanks!

Since you include the file inside a function - GLOBALS cannot be defined there (neither a class). What you probably want to do is to include class.bar.php outside (of foo()):
<?php //myScript.php
include '../../php/class.bar.php';
echo("Calling foo(): ");
foo();
function foo() {
$bar = new bar();
$bar->doSomething();
}
?>

Related

Do I need to declare a variable before initialise it in PHP constructor

I have a question about variable declare in PHP, I know this question may be little bit stupid. I have the following code
<?php
Class Test{
function __construct(){
$this->test = 'helloworkd';
}
function test(){
echo $this->test;
}
}
$test = new Test();
$test->test();
It seems like I can use the test variable without declaring it. My question is why the test() method can access the test variable? Is the test a global variable?
Thanks for your help!
My question is why the test() method can access the test variable?
PHP unlike some other languages allows you to assign values to variables without first declaring them. The interpreter will initialize them for you. This is poor practice because it makes code harder to read and debug, and because it can cause errors if you try to read a variable that was never declared:
<?php
$nonexistentArray['key'] = 7; //Bad practice, but PHP won't complain
$a = $fakeArray['key']; //Undefined variable error
Even in the second case, PHP will continue to execute the rest of the script, but it will complain.
Is the test a global variable?
No. It lives in the local scope.
<?php
function myFunc(){
//$arr was never declared, but PHP won't complain
$arr['key'][]=7;
}
myFunc();
//Undefined var error. The $arr that was initialized in myFunc is not global
print_r($arr);
A good IDE will complain if you try to use a variable that you never declared. In your case, when in the constructor you do:
$this->test = 'helloworkd';
PHP will initialize this class property for you. Now the rest of your code can use it, including the test() method. If it seems like a global var, it's not. It's a class property. If you tried to access it as just test from outside the class, you would not be able to. You'd have to use the accessor operator -> in $test->test or $this->test.
Many "test"! You have asign test="helloworld" in the contructor, so it takes a value for every new Test() is made.
$x = new Test();
$y = new Test();
echo $x->test(); //"helloworld"
echo $y->test(); //"helloworld"
I would declare your variable. This makes the code more readable for yourself any any others that see your code.
For example:
<?php
Class Test {
public $test;
function __construct($test){
$this->test = $test;
}
function test(){
echo $this->test;
}
So now we have a public variable that is accessible through an instance of this class by calling
$instance->test;
If you do not want this then you can change public to private or protected
You can read about this here: http://php.net/manual/en/language.variables.scope.php
Whatever you pass as an argument when creating an instance of this class will be assigned to the $test variable.
My question is why the test() method can access the test variable?
It can't. It is trying to access a constant test, if you want to access the class variable, use $this->test.
For example:
<?php
echo foo;
Will echo out a string "foo" and also spits out a notice: Use of undefined constant foo - assumed 'foo' in ...
<?php
class test{
public $test;
public function __construct(){
$this->test = 'helloworkd';
}
$newtest = new Test();
echo $newtest->test;
?>

PHP accessing global variable set in class

I'm missing something fundamental here. We need to access the variable $myvar that is set in the function do_stuff. Here's a generalized snippet of the class where the function exists. The class and it's functions all work just fine.
class TestClass {
public function do_stuff() {
global $myvar;
$myvar= 'the value we want';
}
}
Now, later on here's where it goes wrong...
$TestClass = new TestClass();
$TestClass->do_stuff();
function get_var() {
global $myvar;
echo $myvar; // here the value does NOT exist
}
get_var();
echo $myvar; // but here the value DOES exist
So what am I missing as to why the variable exists when we access it outside of a function, but it does not exist when accessing inside a function?
Notes: This is a simplified version of what we're doing, so although this example is trivial, it illustrates the issue we're facing. I also understand that many people don't like global variables. Given the legacy code and framework being used, we need to solve this specific problem.
Thank you for you help!
class TestClass {
public function do_stuff() {
global $myvar;
$myvar= 'the value we want';
}
}
function get_var() {
global $myvar;
echo $myvar; // here the value does NOT exist
}
get_var();
echo $myvar; // but here the value DOES exist
Will be what you got, now if you actual use the class and execute it.
class TestClass {
public function do_stuff() {
global $myvar;
$myvar= 'the value we want';
}
}
function get_var() {
global $myvar;
echo $myvar; // here the value does NOT exist
}
$TestClass = new TestClass();
$TestClass->do_stuff();
get_var();
echo $myvar;
Should echo what you want. Order of operations still matter, just because something is placed in a class doesn't mean it get's magically executed.
For example this
get_var();
$TestClass = new TestClass();
$TestClass->do_stuff();
Is still unset
To be completely honest though, I would avoid using global at all because the main issue with that method is that you cannot trace where the value in it is from, For example using a class to hold the value, it is then very easy to find the class. To me use of code like that is just lazyness on the part of the developer.
UPDATE: that is odd then because running this:
class TestClass {
public function do_stuff() {
global $myvar;
$myvar= 'the value we want';
}
}
$TestClass = new TestClass();
$TestClass->do_stuff();
function get_var() {
global $myvar;
echo $myvar; // here the value does NOT exist
}
get_var();
echo $myvar;
ON WAMP with php 5.4 works fine and outputs
the value we wantthe value we want
Note though I ran it as a complete block, in the same file. But again I feel I have to say that you would be better off injecting the value into the function instead of mucking with global it's something that should be done away with IMO.
$TestClass = new TestClass();
get_var($TestClass->do_stuff());
What's the purpose of get_var, I know this is an example. But what are you trying to do that you need global for. There are other things that can be done such as throw and catch exceptions, debug_backtrace(), dependancy injection being the obvious one.
here is just one of may articles you can find on the subject.
http://c2.com/cgi/wiki?GlobalVariablesAreBad
As a professional web developer and a CIO, I have to agree with them.
The correct would declare the variable outside the function and then use global, or this to call the variable.
$myVar = null;
funcion get_var(){
global $myVar;
$myVar = 10;
for ($i = 0; i < $myVar; $i++){
var_dump($i);
}
}
Works fine for me.

How does Zend framework manage to use $this outside of a class?

I am fairly new to OOP in PHP, and I tried to create my own layout class.
In my case, it works like this:
$layout = new Layout('some name'); // title
$layout->setStyle('somestyle.css');
$layout->addDiv('id/class', $content );
Then, just in order to see how professionals create templating applications, I started reading Zend website, the manual part where creation of layouts is covered, but I am failing to understand how is it possible that they have a separate PHP file to initialize the layout, but the layout itself is located in a regular html file.
In that file, they are using $this variable among HTML tags, but how can they do it without triggering 'use of $this variable outside of class context' error? As far as I can see, the tags are not internally included into any class, nor is any PHP file included into the template file.
Could you please provide a simple explanation / example of how this works?
template.php
<p><?php echo $this->foo(); ?></p>
class.php
class Bar {
public function render() {
include 'template.php';
}
public function foo() {
return 'foo';
}
}
$bar = new Bar;
$bar->render();
This is how. The template file is included in a class method.
They're using include() and/or require. Anything that is loaded up via those functions acts as if it was literally cut&pasted into calling code. e.g.
includeme.php:
<?php
$var = 'foo';
Some other file:
<?php
function bar() {
include('includeme.php');
echo $var; // ouputs "foo"
}
echo $var; // outputs "PHP Notice: Undefined variable: var
In object code:
includemephp:
<?php
$this->var = 'foo';
echo $this->whatever;
And some other file:
class foo {
public $var;
public $whatever = 'yoohoo!';
function bar() {
include('includeme.php');
echo $this->var;
}
}
$x = new foo();
$x->bar(); // outputs `yoohoo!foo`
Since the included text is DIRECTLY inserted into the code at the point include() is called, as if the contents of the included file were literally cut/pasted at that spot, there is no difference for $this inside the included file - it's operating inside that method call, and $this will work as expected.
But if you had a simple file like this:
<?php
include('includeme.php');
You will get the Using $this when not in object context error, because there is no object/method surrounding the included code.

Modify the class property inside the class function

I got the code from php.net website:
<?php
class foo {
public $foo;
public $bar;
public function foo() {
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
echo <<<EOT
I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
EOT;
?>
But I'm confused, what is every "foo" stand for? Can you really modify the properties(variables) inside a method(function) without calling the function?
I write a similar code but nothing happened
<?php
class page {
public $meta;
public $buttons;
public function show_meta() {
$this->meta = "I'm a website";
$this->buttons = array(
"home" => "index.php",
"about" => "about.php"
);
}
}
$index = new page();
echo $index->meta;
echo $index->buttons["home"];
?>
I'm a php learner, I need your help please :)
function foo is a PHP4-style constructor (note that the function has the same name as the class). In PHP5 you would write function __construct() instead.
new foo() actually calls the constructor, initilizing your variables.
On the first, yes, because your properties are public.
On the second case, you have reference with a string to remove the warning.
$index->buttons["home"];
You never call show_meta so the array is never populated.
this is the old php syntax for constructor methods. Constructors are Special methods, which are called, whenever a new object from the class is created. The new naming convention for constructors say, all constructors are named __construct.
To get the code above to work, you have to call show_meta, before accessing the two vars or make show_meta the constructor.
$index = new page();
$index->show_meta();
echo $index->meta;
echo $index->buttons["home"];
btw.. home is a string and should be inside "", or you raise at least a warning.

PHP access external $var from within a class function

In PHP, how do you use an external $var for use within a function in a class? For example, say $some_external_var sets to true and you have something like
class myclass {
bla ....
bla ....
function myfunction() {
if (isset($some_external_var)) do something ...
}
}
$some_external_var =true;
$obj = new myclass();
$obj->myfunction();
Thanks
You'll need to use the global keyword inside your function, to make your external variable visible to that function.
For instance :
$my_var_2 = 'glop';
function test_2()
{
global $my_var_2;
var_dump($my_var_2); // string 'glop' (length=4)
}
test_2();
You could also use the $GLOBALS array, which is always visible, even inside functions.
But it is generally not considered a good practice to use global variables: your classes should not depend on some kind of external stuff that might or might not be there !
A better way would be to pass the variables you need as parameters, either to the methods themselves, or to the constructor of the class...
Global $some_external_var;
function myfunction() {
Global $some_external_var;
if (!empty($some_external_var)) do something ...
}
}
But because Global automatically sets it, check if it isn't empty.
that's bad software design. In order for a class to function, it needs to be provided with data. So, pass that external var into your class, otherwise you're creating unnecessary dependencies.
Why don't you just pass this variable during __construct() and make what the object does during construction conditional on the truth value of that variable?
Use Setters and Getters or maybe a centralized config like:
function config()
{
static $data;
if(!isset($data))
{
$data = new stdClass();
}
return $data;
}
class myClass
{
public function myFunction()
{
echo "config()->myConfigVar: " . config()->myConfigVar;
}
}
and the use it:
config()->myConfigVar = "Hello world";
$myClass = new myClass();
$myClass->myFunction();
http://www.evanbot.com/article/universally-accessible-data-php/24

Categories