This question already has answers here:
Use global variables in a class
(4 answers)
Closed 10 years ago.
I'm starting with OOP in PHP and there is something I'd like to do. Let me show an example:
classes.php
<?php
class a {
public function a() {
echo 'a';
}
}
class b {
public function calla() {
$x->a();
}
}
?>
index.php
<?php
include('classes.php');
$x = new a();
$d = new b();
$d->calla();
?>
Is this possible? I know I can do something like:
class b {
public function calla($object) {
$object->a();
}
}
and
$d->calla($x);
but is the first example possible to do?
So you want to use $x as global variable? Syntax is the same, object or not:
class b {
public function calla() {
$GLOBALS['x']->a();
}
}
... or:
class b {
public function calla() {
global $x;
$x->a();
}
}
Of course, it's a horrible design that injects hard to track dependencies and will probably lead to unexpected side effects and head-scratching.
Additionally, a() is a poor method name for class a because it's the PHP 4 syntax for constructors. If you run this code:
<?php
class a {
public function a() {
echo 'a';
}
}
class b {
public function calla() {
$GLOBALS['x']->a();
}
}
$x = new a();
$d = new b();
$d->calla();
... you'll see that a() runs twice. Guess why?
I think I understand what you're trying to ask but you're mixing up parameters visibility concept with object passing in class methods. So let's clean up...
In your classes.php file the method calla() of the class b as absolutely nothing to do with class a, unless $x itself is an instance of the class a.
In your index.php file you instantiate $x as class a, but it is a global variable, and the class b has no visibility on it. Moreover, your call to $d->calla() would return an error because you are accessing a private method from outside.
Your third example gets closer to the solution, passing the instance to the calla() method helps class b seing the instance of class a, I guess you want to edit your index.php file to:
<?php
include('class.php');
$x = new a();
$d = new b();
$d->calla($x);
?>
But this still won't work until you change the private methods to public ones.
Related
I have 2 classes declared like in the example below.
class A{
protected $process;
public function __construct() {
......
$this->process=new B();
}
public function do_something(){
....
}
}
class B{
// content not important
// I need to call do_something from class A
}
My question is, how can I call from class B the method do_something() from class A? Is it possible?
From your example it is impossible for instance of B to know that it is instantiated and stored by an instance of class A. You need to create that connection explicitly in some way.
I didn't think this would even work, but apparently you can pass instance of A to B before A is even done with its constructor:
class A {
protected $process;
public function __construct() {
$this->process = new B( $this );
}
public function do_something() {
var_dump( 'do_something' );
}
public function test() {
$this->process->test();
}
}
class B {
public function __construct( A $a ) {
$this->a = $a;
}
public function test() {
$this->a->do_something();
}
}
$a = new A();
$a->test(); // do_something
It's hard to give an advice on what the best approach for your particular case would be, as we don't know what either A or B does.
There's a few ways to achieve this. One way would be to make B and extension of A - thereby allowing all methods of the class A to be callable on the object B. Another way is to create a new object of A inside B and call that method. Or you can pass
Here's an example where B is extended from A. By doing this, all properties and methods of A can be called on B, unless overwritten in B.
class A {
public function doSomething(){
echo "doSomething() called in A";
}
}
class B extends A {
public function someMethod() {
$this->doSomething();
}
}
$b = new B();
$b->someMethod();
The above would output doSomething() called in A.
Or, you can create an object A and call that method inside B.
class B {
public function someMethod() {
$a = new A();
$a->do_something();
}
}
$b = new B();
$b->someMethod();
After reading all the answers and doing some research i think that the best method for me was the use of Traits
"Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies."
So i declared a Trait with the method do_something and call that method from Both class A and Class B
Thanks
So I came across a code like this and it makes use of one of the Bar class properties called testObj while it's not defined so I expected this to be wrong but I tested it my own and no errors:
<?php
class Foo{
public function __construct()
{
echo 'Echo From Foo';
}
}
class Bar{
public function __construct(Foo $foo)
{
$this->testObj = $foo;
}
}
$bar = new Bar(new Foo);
Why is that so? Does this have anything to do with the "Dynamic/Loose Type"ness of PHP or something else?
Properties can be defined dynamically and their visibility is defaulted to public as can be seen in the example below:
class X {
public function test()
{
$this->y = 'test';
}
}
$x = new X();
$x->test();
echo $x->y; // test
You can also do this without being in the class, so if I wanted to add another property, I could just do the following:
class X {
public function test()
{
$this->y = 'test';
}
}
$x = new X();
$x->test();
echo $x->y; // test
$x->z = 'blah';
echo $x->z; // blah
Remember, when a class in instantized it is just an object which can be manipulated as any other object.
Note: If I don't call test() in the above code, it will result it an error (undefined property) because the variable has not been defined except in the test() function.
Live Example
Repl
This is perfectly normal, you can dynamicaly assign every propteries to a PHP class without error. Event if you should declare it properly to keep track of your object structure.
If you want it to throw an error, you can use the __get magic function and ReflectionClass to determine wich property is setted and wich you can't set even if I didn't see any advantage of doing this.
I've experimented with Late Static Bindings and tried different combinations of using self :: and static :: and then got something really strange. I do not understand how it is possible that the script executes without any warning (error_reporting = E_ALL). Could anyone try to explain how that works?
class A {
private function privateWho() {
echo __CLASS__.PHP_EOL;
}
public function test() {
B::privateWho();
}
}
class B extends A {}
$b = new B();
$b->test(); // prints A
I'm at a loss. I have gone over my two classes extensively for hours. Nothing is static, nothing is being statically referenced, yet I cannot get rid of this error.
Class A's file (ClassA.php)
<?php
namespace MyProject\A;
require_once "B.php";
use MyProject\B as B;
class A
{
private $privateVariable;
public function __construct()
{
$b = new B\B();
$this->privateVariable = $b->something;
}
}
Class B's file (B.php)
<?php
namespace MyProject\B;
class B
{
public $something;
public function __construct()
{
$this->something = "Some (dynamic) string value";
}
}
I am not new to classes, however I've never had this issue before (without having at least a static variable or method or static reference).
The errors I get are:
Strict Standards: Accessing static property MyProject\B\B::$something as non static in A.php on line (this line: $this->privateVariable = $b->something)
and
Notice: Undefined property: MyProject\B\B::$something in A.php on line (this line: $this->privateVariable = $b->something)
I think anyone reading this understands that I want to get B's variable $something into A's variable $privateVariable while maintaining class B as an instance within class A upon instantiation of class A like:
<?php
namespace MyProject\Something;
require_once "A.php";
use MyProject\A as A;
$a = new A\A()
// $a's private variable $privateVariable should be set to "Some (dynamic) string value"
Any help regarding this issue is greatly appreciated!
EDIT
Changed code to better reflect original code (changing use AS to use as and changing the way use was calling the appropriate classes
PHP Version: 5.6
EDIT 2
I honestly have no idea what was going on.
I uploaded my files to the server
I then checked that they were uploaded properly
I was still receiving those errors
I then commented all my code except the lines above
I still received the error
I then uncommented the lines I had just commented out (using CTRL+Z)
I then reuploaded the document
I ensured that they were uploaded properly
Now everything works.
I apologize for this issue but I think it was more of a bug than an actual code issue. I'll just blame Godaddy for this one (yes, I know Godaddy is great choice sarcasm)
Here, full working single file example:
namespace MyProject\ClassA {
use MyProject\ClassB\B;
class A {
private $privateVariable;
public function __construct() {
$b = new B();
$this->privateVariable = $b->something;
print $this->privateVariable;
}
}
}
namespace MyProject\ClassB{
class B{
public $something;
public function __construct()
{
$this->something = "Some (dynamic) string value";
}
}
}
namespace MyProject\Something {
use MyProject\ClassA\A;
$a = new A();
}
Test it.
Update:
You use :
use MyProject\A as A;
$a = new A\A();
But use MyProject\A point to a namespace not a class.
So this is right:
use MyProject\A\A as A;
$a = new A();
And another note use this : use \MyProject\A\A with \ at first place.
I think your namespaces are incorrect. My bet is PHP couldn't instantiate the class and assumed you were calling it statically. I cleaned up the namespaces and created one giant file and it runs fine
namespace MyProject\ClassB;
class B
{
public $something;
public function __construct()
{
$this->something = "Some (dynamic) string value";
}
public function getStr() {
echo $this->something;
}
}
namespace MyProject\ClassA;
use \MyProject\ClassB\B as B;
class A
{
private $privateVariable;
public function __construct()
{
$b = new B();
$this->privateVariable = $b->something;
$b->getStr();
}
}
namespace MyProject\Something;
use \MyProject\ClassA\A as A;
$a = new A();
There's an observation worth noting: You don't write use ... AS ... you write use ... as .... AS should be all lower cases. Therefore; the correct use statement should have read: use MyProject\ClassB as cB. The Code-Excerpt below will illustrate these points.
<?php
namespace MyProject;
require_once "ClassB.php";
use MyProject\B as cB;
class A {
private $privateVariable;
public function __construct() {
$b = new cB();
$this->privateVariable = $b->getSomething();
}
}
?>
<?php
namespace MyProject;
class B{
public $something;
public function __construct(){
$this->something = "Some (dynamic) string value";
}
// YOU MAY WANT TO CREATE A FUNCTION TO GET THE SOMETHING
public function getSomething(){
return $this->something;
}
}
Or using aliasing....
<?php
namespace MyProject\ClassA;
require_once "ClassB.php";
use MyProject\ClassB as cB;
class A {
private $privateVariable;
public function __construct(){
$b = new cB\B();
$this->privateVariable = $b->getSomething();
}
}
?>
<?php
namespace MyProject\ClassB;
class B{
public $something;
public function __construct(){
$this->something = "Some (dynamic) string value";
}
// YOU MAY WANT TO CREATE A FUNCTION TO GET THE SOMETHING
public function getSomething(){
return $this->something;
}
}
To run the code (The First Example - without Aliasing):::
<?php
namespace MyProject\Something;
use MyProject\A as A;
require_once "A.php";
require_once "B.php";
$a = new A();
var_dump($a);
// PRODUCES:::
object(MyProject\A)[1]
private 'privateVariable' => string 'Some (dynamic) string value' (length=27)
Test it out yourself HERE.
I stumbled across a very wired error in php:
class A {
public $var = "test";
public function __construct() {
$this->var = "test2";
$b = new B;
$b->method();
}
}
class B extends A {
public function method() {
$c = new C;
$c->method();
}
}
class C extends B {
public function method() {
echo $this->var;
}
}
$a = new A;
I get the output "test", but I do not know why, cause the variable var should be overwritten in Class A.
If I output $var in Class A it says "test2", if I output it in Class B it says "test"…
The code on your question won't work because of the circular references (eg: $b = new B in A's constructor), which will cause PHP to run out of memory. You really shouldn't be instantiating children classes in a parent class.
That being said, by what you are describing, it sounds like you are defining a constructor in B, which overrides the parent constructor. In PHP children classes don't implicitly call the parent constructor (unlike in languages like Java).
So, it just inherits the original value for $var (ie: "test"), which is never changed. If you are overriding __construct() in B, you'll have to explicitly call the parent constructor, like:
class B extends A {
public function __construct() {
parent::__construct();
}
}
And that should give you "test2" when you do something like:
$b = new B;
echo $b->var;
See this demo: http://ideone.com/Q9Bp8
What is the best way to have 3 classes, where the third and second can access variables of the first class?
The answer is, it depends on what you are doing. It sounds like you are not understanding how OOP works, which is a bigger problem. In general you only use inheritance when the children classes could reuse code from the parent class, and/or there is some sort of is-a or has-a relationship.
If your classes don't fit this model, just make the 3 classes independent, and hold a reference to the first class in your other classes. For example:
class A {
public $n = 0;
public function change($n) {
$this->n = $n;
}
}
class B {
public function __construct($a) {
$this->my_a = $a;
}
public function get() {
return $this->my_a->n;
}
}
$a = new A();
$b = new B($a):
echo $b->get(); // 0
$a->change(10);
echo $b->get(); // 10
See this demo: http://codepad.org/xL1Dzs0W