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.
Related
=== Base.php ===
<?php
class Base
{
public static function e()
{
static $number = 0;
$number++;
var_dump($number);
}
}
=== A.php ===
<?php
class A extends Base {}
=== B.php ===
<?php
class B extends Base {}
=== test.php ===
function __autoload($classname)
{
require_once("{$classname}.php");
}
Base::e();
A::e();
B::e();
php test.php, result is:
int(1)
int(2)
int(2)
Why not result is 1,1,1?
Try
require "Base.php";
Base::e();
require "A.php";
A::e();
vs.
require "Base.php";
require "A.php";
Base::e();
A::e();
The former will yield int(1) int(2), while the latter yields int(1) int(1).
Why?
When a class is bound, the static variable content is copied at exactly that moment how it currently is. There is no backing up of the original value of the static variable.
That implies, when the static variable is 0 when class A is bound, A::e() will have 0 as static value; in case it's 1, A::e() will also have 1 as value.
Similar for B::e() then, as Base::e() and A::e() are independent as the values are copied (no references). It will also have the same static variable Base::e() has at the binding time of B.
I did some research on this problem and it is really weird.
Static properties inside methods remain their state between instances of object. Which may be confusing. Also there are two statics one is the static function and the other one is static variable inside method.
It may be connected with autoloader. I did similar example with your but without using static methods but using static variable inside method. The result is 1:1:1 using both autoloader and same file.
<?php
class Base
{
public function t()
{
static $number = 0;
$number++;
var_dump($number);
}
public static function e()
{
static $number = 0;
$number++;
var_dump($number);
}
}
$base = new Base();
$base->t();
$a = new A();
$a->t();
$b = new B();
$b->t();
Also if you won't execute Base::e() the result is correct.
I've did require_once without autoloading and it still works. So it is definitly because of autoloader.
If you put
require_once "Base.php";
require_once "A.php";
require_once "B.php";
instead of autoloader function it works. Why is that I have no idea I've tried to find anything considering static variables with autoloader but without success. However, this answer may give you some clue.
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.
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?
Normaly I would include my class file before I create an object. My question is how I can include a class file only in my main file and then use it method in another class? Here is my code:
main file:
require_once("class.a.php");
require_once("class.b.php");
var $a;
function main () {
$a = new class.a();
$b = new class.b();
}
class b:
class b {
var $a;
function __construct() {
$this->a = class.a::method();
}
}
This seems to work in some older PHP version but it gives an error file class.a.php not found in some new PHP version.
Edit: I've corrected my question: class.b uses direct calls to method from class.a. This gives me an error class.a.php not found. I can fix this error when I add a require_once("class.a.php") to class.b.php like this:
require_once("class.a.php");
class b {
var $a;
function _constructor() {
$this->a = class.a::method();
}
}
But then I have two includes and also this doesn't work with an update version of php?
Well, new class.a() should create a syntax error as . is not a valid operator anywhere apart from string concatenation. You want
class a {
// do something
}
$a = new a();
As to the require_once, well, once you have included or required a file in a PHP script, all of the classes/functions/variables/constants/etc. will continue to persist in all other files which are included after the require. So your problem here is clearly the syntax problem.
Additionally, you may want to consider modifying the following:
var $a; is outdated, it should be public $a (or protected or private). var is still valid because it is backwards-compatible with PHP 4, but it is generally a bad idea.
It is __construct not _constructor
a::method(); means "Call the static method of class a". You want something like $this->a = new a(); $this->a->method();
You should NOT have dots (.) in class names.
And you might want to consider using an autoloader
Change the name of your classes as stated on other answers. Make them as "a" and "b". You have to use dependency injection on class b.
b {
public $a;
function __construct(a $a) {
$this->a = $a; // now you have the instance of class.a in your class.b
}
}
And your main.php
require_once("class.a.php");
require_once("class.a.php");
function main () {
$a = new a()
$b = new b($a);
$b->a->method(); // call the method of a
}
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().