There are two classes, each one in its own file:
<?php
namespace test;
class calledClass {
private $Variable;
function __construct() {
global $testVar;
require_once 'config.php';
$this->Variable = $testVar;
echo "test var: ".$this->Variable;
}
}
?>
and
<?php
namespace test;
class callingClass {
function __construct() {
require_once 'config.php';
require_once 'calledClass.php';
new calledClass();
}
}
new callingClass();
?>
and simple config.php:
<?php
namespace test;
$testVar = 'there is a test content';
?>
When I start callingClass.php (which creates object calledClass), the property $Variable in calledClass is empty. But when I start calledClass.php manually, it reads meaning $testVar from config.php, and assumes it to $Variable.
If I declare $testVar as global in callingClass, it helps - calledClass can read $testVar from config.php.
Can somebody tell me why an object created from another object can't declare variables as global, and use them?
When including (include/require) a file inside a function, all variable declarations inside that file get the scope of the function. So $testVar is created within the scope of callingClass::__construct. Since you use require_once, it will not be re-created elsewhere inside calledClass::__construct! It works when calling only calledClass since you're actually including the file for the first time there.
It has nothing to do with OOP at all, just the rules of function scope and your particular use of require_once.
Related
I'm starting with OOP in PHP and I have an issue with global variables.
Example of my current structure:
test.php REQUIRES globals.php and also INCLUDES classes.php.
globals.php has this code:
global $something;
$something = "my text";
and classes.php looks like this:
global $something;
class myClass {
public $abc = "123";
public $something;
public function doSomething() {
echo $this->abc."<br>";
echo $this->something;
}
}
$class = new myClass();
$class_Function = $class->doSomething();
print_r($class_Function);
At the end, test.php only shows "123".
I tried using "include()" instead of "require" for globals.php but didn't work. Neither did including globals.php in classes.php.
$this->something was never initialized. The global $something is totally outside of scope and is not related to the class attribute $this->something. If you need to access a global inside a function or method you need to declare it as global:
public function doSomething() {
global $something;
echo $this->abc."<br>";
echo $something;
}
However you need to stop using globals because is not a good solution. If you need do define some constant values that are global to your system it's prefered to use define()
define("SOMETHING","My text")
And then you can access it in any part of your code:
echo SOMETHING;
Also see: PHP global variable scope inside a class
and Use external variable inside PHP class
I have two classes, class A and class B, and in a function in class A I want to call a function in B, but the it also requires constants from another file. After requiring both the config.php and classB.php files, I am able to create an instance of class B, but when I try to call the function in B, it gives me a warning saying the constant has not been defined.
In config.php:
$constant = 'blah';
Inside class A I have:
function functionA() {
require_once "config.php";
require_once "classB.php";
$b = new B();
$b -> functionB($constant);
}
The call to function B is giving an error saying $constant is not defined, but when I call new B() there is no problem. Am I doing something wrong?
Aron is correct. In this case you want to use include or require. You must make sure that you have no function or class declarations in the files you're including though.
This is occurring because the require will not occur on every call to the method, just the first. The subsequent calls to the method will result in an undefined variable error.
Additional top tip: You can return values from included files to assign them directly to a variable
A.php:
return 'abc';
B.php:
Class B {
public static function load()
{
$x = include 'A.php';
var_dump($x);
}
}
I imagine that your code should look as follows:
function functionA() {
require "config.php";
require_once "classB.php";
$b = new B();
$b -> functionB($constant);
}
use the sentence include 'config.php';
instead of require_once, if your config.php file just has variable declarations.
My understanding of including a file in a function was that it stays within that function scope:
If the include occurs inside a function within the calling file, then all of the code contained in the called file will behave as though it had been defined inside that function. So, it will follow the variable scope of that function.
But when I do this, the second one clashes with the first and tells me the class is already declared!
Run this php page to see the errors (you'll need all three PHP pages)
<?php
class TestOnce
{
function __construct()
{
$this->includeOnce();
}
function includeOnce()
{
//This should include it once
include_once "once.php";
var_dump( $once );
}
function includeSomethingThatIncludesOnce()
{
include_once "includeonce.php";
var_dump( $once );
}
}
$test = new TestOnce();
$test->includeSomethingThatIncludesOnce();
?>
This also inlcudes once, but is told it's already included which it shouldn't be in that function/
<?php
//This should include it once
include "once.php";
var_dump( $once );
?>
This is "once" which declares the class and an instance variable
<?php
class Once
{
}
$once = new Once();
?>
Why aren't the includes restricted to the scope of the function? How would I achieve that?
Is there a way to use a global variable everywhere in the code?
I want to use a Path variable to the located configured Folder in each Path I'll declare in my code.
Here's my Code:
Index.php
<?php
require_once('Common.php');
require_once('Path.php');
?>
Common.php
<?php
$RootPath = '.';//in this case its root
//add the RootPath for global using
$GLOBALS['RootPath'] = $RootPath;
?>
Path.php
<?php
class Path {
public static $TemplatePath = $GLOBALS['RootPath'].'/Template.php';
}
?>
This won't work because it says, "Parse error: syntax error, unexpected T_VARIABLE" when I try to call $GLOBALS when declaring a static variable.
Is there a way to do this?
Thanks in Anticipation
Alex
What you are looking for are constants.
It's very common to use them to define certain path's, f.e.
define('PATH_ROOT', $_SERVER['DOCUMENT_ROOT']);
define('PATH_TEMPLATES', PATH_ROOT.'/templates');
Class constants and static class variables cannot be initialized with dynamic data.
What about defining method instead?
class Path {
public static getTemplatePath()
{
return $GLOBALS['RootPath'].'/Template.php';
}
}
And why you would keep settings as global variables, and not encapsulate them in some kind of Registry?
whenever you want to use a global variable inside a function that is out of the scope, you must first declare it within the function/class method with "global $varname".
In your case:
Common.php
<?php
$RootPath = '.';//in this case its root
//add the RootPath for global using
// $GLOBALS['RootPath'] = $RootPath; // no need for this, $[GLOBALS] is about the Superglobals, $_SERVER, $_SESSION, $_GET, $_POST and so on, not for global variables.
?>
Path.php
<?php
class Path {
public static $TemplatePath;// = $GLOBALS['RootPath'].'/Template.php';
public method __construct(){
global $RootPath;
self::TemplatePath = $RootPath.'/Template.php';
}
}
?>
Tranform your (bad) public static attribute, to a public static getter/setter.
Also, global variables are a bad pratice, introducing side effect and name collision.
I have A.php and B.php
A.php
<?php
error_reporting(E_ALL);
ini_set("display_errors",1);
class myClass
{
function hello()
{
return 'hello';
}
}
?>
B.php
<?php
error_reporting(E_ALL);
ini_set("display_errors",1);
require_once('/A.php');
$a = new myClass();
testing();
function testing()
{
echo $a ->hello();
}
?>
B.php inherits A.php ,
if i run B.php,but it show
"Fatal error: Call to a member function hello() on a non-object."
So the question is simple, how can i correct this ,but "$a = new myClass();" is not inside the function, since in .NET world can do this, i believe PHP also possible.
And one more question is, what is the modify of function in A.php ,if i have not state private/public/protected?
This is not inheritance. B.php merely includes A.php. This means all the code in A.php becomes available to the execution context of B.php.
Inheritance is a class relationship
class A{}
class B extends A{}
Class B can be said to inherit from A. So, a hierarchy has been formed.
Much as we humans inherit traits from our parents, classes inherit properties from their parents. For this reason, it is very common to talk about these classes in terms of their place in the hierarchy. Class A is a parent to class B. Class B is a child to class A.
But the actual problem you are having, the source of the error message, is a scope issue. You create $a in the global scope but attempt to access it from within a function's scope, in this case testing().
The best way to solve this is to pass your instances of myClass into testing()
$a = new myClass();
testing( $a );
function testing( $myClassObj )
{
echo $myClassObj->hello();
}
And to answer your final question - in PHP5 - class members not explicitly declared with an access modifier become implicitly public.
If you want to use $a in the function, you need to either put
global $a;
as the first line of the function, or access it as $GLOBALS['a']
use this
function testing()
{
global $a;
echo $a ->hello();
}
A couple of things I would change here, I'll explain in a moment.
A.php
<?php
error_reporting(E_ALL);
ini_set("display_errors",1);
class myClass
{
// Here, access modifier.
public function hello()
{
return 'hello';
}
}
?>
B.php
<?php
error_reporting(E_ALL);
ini_set("display_errors",1);
require_once('/A.php');
testing();
function testing()
{
// Here, change where variable is defined to place it in scope.
$a = new myClass();
echo $a ->hello();
}
?>
When no access specifier is given on a method, it defaults to public. However, it is generally better to just declare what you want the method to have. You will appreciate this if you find yourself actively coding in multiple languages as they will each have a different default.
Right now the variable $a is not in the scope of the function testing(). Allow me to rearrange your program and you shall see why. You could have written it, like so:
B.php
<?php
function testing()
{
echo $a ->hello();
}
error_reporting(E_ALL);
ini_set("display_errors",1);
require_once('/A.php');
$a = new myClass();
testing();
?>
You see, where testing() is now defined, $a does not exist. It hasn't been defined yet. So it is not inside testing()'s scope. You'll have to either define $a inside testing() or else pass it in as a parameter. In my first pass, I changed your code to define $a inside testing(). If you will need to use it in multiple functions, then I would suggest changing testing() to take it as a parameter. Like this:
function testing(myClass $a) {
echo $a->hello();
}
Then pass it in this way:
$a = new myClass();
testing($a);
I believe $a is not defined in the function. Try using global $a first, and then calling hello().