Let's say I have a class Bla that contains the variable $x.
I want this variable $x to keep its value for other objects once it's set by the first created object.
For example:
$object1 = new bla(.....);
$object1->setx();
$object1->getx();
$object2 = new bla(.....);
$object2->getx();
So I want:
$object2->getx()
...to give me the value I already set by object1.
I tried using $x as a globale variable inside the class, it turns out that it's not possible.
Can I use it outside the class and then access this variable inside the class?
What are the other methods?
Use static variables if you want them to have one and the same value, available regardless of their class instances (tutorial):
class bla
{
private static $x;
public function setx($x) {
self::$x = $x;
}
public function getx() {
return self::$x;
}
}
$object1 = new bla();
$object1->setx(5);
echo $object1->getx();
echo '<br>';
$object2 = new bla();
echo $object2->getx();
Output:
5
5
class Bla {
static private $x = "X!";
}
If you know what x should be at initialisation then just use the above. If x is computed then you can ensure it's only set once:
class Bla {
static private $x = null;
public function getX(){
if($this->x === null){
$this->x = theLogicToGetX();
}
return $this->x;
}
}
Only the first call will set x and subsequent calls will use that value.
See with example:
<?php
class Foo {
private static $my_static = 'foo';
/**
* Set static class property
*
* #param string $v
*/
public function setStaticValue($v) {
self::$my_static = $v;
}
/**
* Get static class property value
*
* #return string
*/
public function getStaticValue() {
return self::$my_static;
}
}
// show class static property value
echo foo::getStaticValue(); // foo
// now set new value in static property
foo::setStaticValue(' zoo ');
// show value
echo foo::getStaticValue(); // zoo
// make an object of class
$f = new Foo();
// show value
echo $f->getStaticValue(); // zoo
// make new object of class
$f2 = new Foo();
// show value
echo $f2->getStaticValue(); // zoo
It is possible with references
class A
{
private $a;
public function &getA(){return $this->a;}
public function setA($a) { $this->a = $a;}
}
class B
{
public function useA(&$a) { $a+=5 ;}
}
$objA = new A();
$objB = new B();
$objA->setA(5); //seting value of a in A class to 5
$objB->useA($objA->getA()); //modify the reference of A class $a variable in B class object
echo $objA->getA(); //echo the value from A class object
Output: 10
My solution doesn't have static limitations. So it can be used on multiple objects of same class. If you want to have access to class variable by same class objects use static as suggested above by Lukas.
There is also registry pattern which you should take a look at. Registry pattern makes you able to access variable in whole php application.
The idea of a Registry is simple: providing a dynamic possibility for discovering collaborator objects, so that we not hardcode static calls to global objects like Singletons in each of them. In the testing environment, we can fill the Registry with mocks.
class Registry
{
private static $instance;
private $registry = array();
private function __construct()
{
}
public function getInstance()
{
if(self::$instance == null) self::$instance = new Registry();
return self::$instance;
}
public function __set($var,$val)
{
$this->registry[$var] = $val;
}
public function __get($var)
{
if(isset($this->registry[$var]))
return $this->registry[$var];
else throw new Exception("Value $var doesn't exists in registry");
}
}
class A
{
public function useVar()
{
Registry::getInstance()->myVar += 10;
}
public function echoVar()
{
echo Registry::getInstance()->myVar;
}
}
Registry::getInstance()->myVar = 5;
$obj1 = new A();
$obj2 = new A();
$obj1->useVar();
$obj2->echoVar();
OUTPUT: 15
Yeah, you can make this functionality.
From here "global variable" means kind of variables, mentioned in the question.
You can use static variable of the class to store the value of global variable.
class Bla {
static private $x;
}
To access this variable we can use couple of methods:
Make special setters and getters, I would recommend this as most simple and clear way:
class Bla {
static private $x = 'init value';
public function getX() {
return self::$x;
}
public function setX($value) {
self::$x = $value;
}
}
// Usage:
$obj1 = new Bla();
echo $obj1->getX();// init value
$obj1->setX('changed value');
Of course if appropriate you can use just static access syntax (public variables or static setters and getters), which is even more simple and clear, than first method. For example:
class Bla {
static public $x = 'init value';
}
// Usage:
echo Bla::$x;
Bla::$x = 3;
Also take in mind that objects are passing by references in PHP5.
class Bla {
private $date;
public function __construct(DateTime $x) {
$this->date = $x;
}
public function getDate() {
return $this->date;
}
}
$date = new DateTime();
// Usage:
$obj1 = new Bla($date);
$obj2 = new Bla($date);
/* now play with $objN->getDate()->.. and $date->..
* to see, that $x in both objects are referring to same variable. */
Now lets see at some not so good ways.
We can use magic setters and getters, which combined of a phpDoc can "emulate" behaviour of a real object variable (i mean in runtime it will get and set variable and in IDE, which supports phpDoc, you can even see variable in auto-completion). This solution violates the principle of encapsulation, so i wouldn't recommend common usage of it.
/**
* #property mixed $x My global var.
*/
class Bla {
static private $x = 'init value';
public function __set($name, $value) {
if ($name == 'x') {
self::$x = $value;
}
}
public function __get($name) {
if ($name == 'x') {
return self::$x;
}
}
}
// Usage:
$obj1 = new Bla();
echo $obj1->x;// init value
$obj1->x = 'changed value';
Same behaviour without magic we can get using references:
class Bla {
static $storage = 'init value';
public $x;
public function __construct() {
$this->x = &self::$storage;
}
}
Also we can make $x here private and add special access methods, what makes sense only if you HATE to use static syntax (self::).
Related
I'm trying to change a property in my parent class with my child class but I'm not getting the result I'm expecting.
I've done some research (like Change parent variable from child class), but I can't seem to find the problem.
class A {
public $msg;
public function __construct() {
$this->msg = 'foo';
}
public function setMessage($string) {
$this->msg = $string;
}
public function getMessage() {
var_dump($this->msg); // For demo purposes
}
public function triggerB() {
$b = new B;
}
}
class B extends A {
public function __construct() {
parent::setMessage('bar');
}
}
$a = new A;
$a->getMessage();
$a->triggerB();
$a->getMessage();
The output I get is "foo" twice and I expect it to be "foo" "bar".
Could anyone explain me what i'm doing wrong and how I can fix this?
In my actual code I want the child-class to validate some $_POST values, and return the outcome to the Main-class. The parent uses the child to validate.
You are having your object A and creating an instance of it and storing it in the variable $a, in the global scope. And then you are creating another instance of your class B and storing it in a variable $b which is in the scope of the method triggerB().
You can only change the properties of the parent class A if you pass an argument to your another class B.
So something like this should suffice:
<?php declare(strict_types = 1);
class A {
public $msg;
public function __construct() {
$this->msg = 'foo';
}
public function setMessage(string $string) {
$this->msg = $string;
}
public function getMessage() {
var_dump($this->msg); // For demo purposes
}
public function triggerB() {
(new B($this));
}
}
class B {
public function __construct(A $a) {
$a->msg = "bar";
}
}
$a = new A;
$a->getMessage();
$a->triggerB();
$a->getMessage();
This approach is better suited to readability and better dependency management.
Another approach:
<?php declare(strict_types = 1);
class A {
public $msg;
public function __construct() {
$this->msg = 'foo';
}
public function setMessage(string $string) {
$this->msg = $string;
}
public function getMessage() {
var_dump($this->msg); // For demo purposes
}
public function triggerB() {
$this->msg = 'bar';
}
}
class B {
public function __construct(A $a) {
$a->msg = "bar";
}
}
$a = new A;
$a->getMessage();
$a->triggerB();
$a->getMessage();
This is performance wise better, but if you are going to be doing something complex, the first method is better.
Note: The above code is for PHP7.
Your triggerB() method does not actually do anything:
public function triggerB() {
$b = new B;
}
You are creating a new object and assign that to the $b variable. As soon as the method finishes, the $b variable / object ceases to exist.
Also note that the $b variable in your method is is no way related to the $a variable in the global scope so setting any of its properties has no influence on $a.
I would like to ask, if there is a way, to use variables in a class, that were declared out of it.
Example:
$foo = 'bar';
class foobar{
function example(){
echo "foo{$foo}";
}
}
$foobar = new foobar;
$foobar->example();
This code produces a notice: Notice: Undefined variable: foo
Is there a way to make it work? Or is there some work-around?
You could give this argument to your class with a constructor
class foobar{
private $foo;
public function __construct($name) {
$this->foo = $name;
}
}
and then use it.
Or what PeeHaa means, you could change your method to
function example($param){
echo "foo{$param}";
}
and call it like this
$foobar->example($foo);
Use a construct to import it or use the global keyword. You could do something like this:
$var = 'value';
class foobar {
private $classVar;
function __construct($param) {
$this->classVar = $param;
}
}
And initiate it like this:
$var = 'value';
$inst = new foobar($var);
Or you can use global variables (which I wouldn't recommend in this case) and do something like this:
$var = 'value';
class foobar {
global $var;
function show() {
echo $var;
}
}
UPDATE: To use a class within another class, it may be instantiated in the constructor if its instance is needed throughout implementation, or it may be instantiated only when needed.
To create a reference to another class inside the constructor, do something like this:
class class1 {
private $someVar;
function __construct() {
$this->someVar = 'success';
}
function doStuff() {
return $this->someVar;
}
}
class class2 {
private $ref;
private $val;
function __construct() {
$this->ref = new class1();
$this->val = $this->ref->doStuff();
// $this->val now holds the value 'success'
}
}
$inst = new class2(); // upon calling this, the $val variable holds the value 'success'
Or you can call it only when needed, like so:
class class1 {
private $someVar;
function __construct() {
$this->someVar = 'success';
}
function doStuff() {
return $this->someVar;
}
}
class class2 {
private $ref;
private $val;
function __construct() {
// do something
}
function assign() {
$this->ref = new class1();
$this->val = $this->ref->doStuff();
// $this->val now holds the value 'success'
}
}
$inst = new class2(); // the $val variable holds no value yet
$inst->assign(); // now $val holds 'success';
Hope that helps you.
Yes add
class foobar{
function example(){
global $foo;
echo "foo{$foo}";
}
}
** putting it in another class is better though, or passing it to the method you're using is better too **
I have a class Foo with a number of public and private methods. One of those methods is getting rather large, and I would like to fork it off into a separate class specifically for that purpose. Something like this:
<?php
class Foo
{
// ...
public function doX( $a, $b )
{
$x = new FooXDoer;
$x->foo = $this;
return $x->run( $a, $b );
}
// ...
}
class FooXDoer
{
public $foo;
public function run( $a, $b )
{
// ...
}
// ...
}
FooXDoer has access to Foo's public methods and properties through $this->foo.
How can I give FooXDoer access to Foo's private methods and properties, without making them public to the rest of the code which already uses Foo?
Should I create a separate class FooPrivate which has the private methods as public, and which Foo wraps, and then have FooXDoer reference that? What should FooPrivate be called?
Or is my approach completely wrong? How do you solve this problem in general?
Looks like traits solve your problem best in case you use PHP >= 5.4.
If not, I thought of the following solution:
class A {
private static $allowedClasses = array('B');
private $a = 1;
public function __get($property) {
$caller = debug_backtrace(false);
if(!isset($caller[1]))
throw new Exception('Bla bla');
if(!in_array($caller[1]['class'], self::$allowedClasses))
throw new Exception('Bla bla');
return $this->$property;
}
public function testB() {
$b = new B();
$b->instA = $this;
echo $b->getA();
}
}
class B {
public $instA;
public function getA() {
return $this->instA->a;
}
}
class C {
public function getA() {
$instA = new A();
return $instA->a;
}
}
$a = new A();
$a->testB(); // Works ok;
$c = new C();
$c->getA(); // Throws exception here;
This code is definitely not a best practice :) But since it is possible I put it here.
PHP has no friend class concept, from what I've read I wouldn't say it's a bad decision by the php designers...
IMHO, there is no general strategy, as the problem or question is too broad: there are too many factors to consider:
how many private properties and methods of Foo are needed in run()?
from an abstraction point of view: how closely is run() entangeled in Foo? Does it really "deserve" to be in an independent class?
will you ever use FooXDoer outside of Foo?
Two ideas for solutions:
hand over the needed data from foo to fooDoer, either value for value or by implementing a compileRunData() on Foo that returns an array or an object
public function doX( $a, $b )
{
$x = new FooXDoer;
$workEnvironment = $this->compileRunData();
$x->setEnvironment( $workEnvironment );
$x->foo = $this;
return $x->run( $a, $b );
}
or use inheritance, especially the concept of protected properties:
abstract class FooAbstract
{
protected $_basicVar1;
protected function basicMethod1(/*...*/) {
//...
}
// ...
}
abstract class FooRunner extends FooAbstract
{
protected $_runVar1;
protected function runMethod1(/*...*/) {
//...
}
public function run($a, $b) {
// ...
}
}
public class Domain_Model_Foo extends FooRunner
{
}
edit: hey, SO didn't show me there was already an answer. Yea, thought about traits, too, but haven't used them until now so can't really comment on them
I'm a totally newbie in class writing in PHP, started a couple days ago.
I'd like to declare a new "public property" inside a method to be used in other methods.
This is what I thought (Of course it doesnt' work!):
class hello {
public function b() {
public $c = 20; //I'd like to make $c usable by the method output()
}
public function output() {
echo $c;
}
}
$new = new hello;
$new->output();
Thanks in advance for any tips.
I'd like to declare a new "public property" inside a method to be used in other methods.
If the other methods are part of the same class, you don't need a public property, a private property will fit your needs. Private properties are accessible within the same class only which helps to keep things simple.
Also understand the difference between declaring a property and assigning a value to it. Declaring is done when the code is loaded, assigning when it executes. So declaring (or defining) a property (private or public) needs a special place in the PHP syntax, that is in the body of your class and not inside in a function.
You access properties inside the class by using the special variable $this in PHP.
The pseudo-variable $this is available when a method is called from within an object context. $this is a reference to the calling object (usually the object to which the method belongs [to]). From PHP Manual
Private property example:
class hello {
private $c; # properties defined like this have the value NULL by default
public function b() {
$this->c = 20; # assign the value 20 to private property $c
}
public function output() {
echo $this->c; # access private property $c
}
}
$new = new hello;
$new->output(); # NULL
$new->b();
$new->output(); # 20
Hope this is helpful. You use a private property because everything else in your program does not need to care about it, so inside your class you know that nothing else can manipulate the value. See as well VisibilityDocs.
Every variable of the class is public when you define it inside of a method (function)! You can do this the following way:
class hello {
public function b() {
$this->c = 20;
}
public function output() {
echo $this->c;
}
}
$new = new hello;
$new->output();
or let function b() return $c and then pass it as a variable to output():
class hello {
public function b() {
return $c = 20;
}
public function output($c) {
echo $c;
}
}
$new = new hello;
$c = $new->b();
$new->output($c);
Remember all variables inside a function are ONLY accessable from within that particular function...unless you use $this of course, which makes the variable a class property!
Also, it's recommended to only return variables...echo is only for the real output, the pure HTML, the template, your view, if you know what I mean :)
Try this instead:
class hello {
public $c = null;
public function b() {
$this->c = 20; //I'd like to make $c usable by the method output()
}
public function output() {
echo $this->c;
}
}
class hello {
public $c;
public function b() {
$this->c = 20;
}
public function output() {
$this->c;
}
}
Note: If you need to use a property in another method you don't need to declare that method as public, you should declare the property as private, and you'll have access to your property with no problem:
class hello {
private $c;
public function b() {
$this->c = 20;
}
public function output() {
$this->c;
}
}
class hello {
public $c;
public function b() {
$this->c = 20; //I'd like to make $c usable by the method output()
}
public function output() {
return $this->c;
}
}
$new = new hello;
echo $new->output();
class hello {
var $c;
function __construct() { // __construct is called when creating a new instance
$this->c = 20;
}
public function getC() {
return $this->c;
// beter to return a value this way you can later decide what to do with the value without modifying the class
}
}
$new = new hello; // create new instance and thus call __construct().
echo $new->getC(); // echo the value
Rewrite this code like this :-
class hello {
public $c;
public function b() {
public $this->c = 20; //I'd like to make $c usable by the method output()
}
public function output() {
echo $this->c;
}
}
$new = new hello;
$new->output();
How do I use an object (along with its methods and properties) when I'm inside an object?
Say I have useless classes like these:
class Fruit {
private $name; // Name of the fruit.
private $health = 10; // 0 is eaten, 10 is uneaten.
private $object; // This is a PHP object.
public function __construct($name) {
$this->name = $name;
}
public function set($varname,$value) {
$this->$varname = $value;
}
}
class Eater {
private $name;
public function eat($object) {
$object->set('health',0); // I know I can pass and modify objects like this.
// The object is passed by reference in PHP5 (but not 4), right?
}
}
And I use it as such:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->eat($apple);
?>
But if I modify the Eater class like so:
class Eater {
private $name;
private $objectToEat; // Let's say if I need the object to be over here instead of in a method.
public function set($varname,$value) {
$this->$varname = $value;
}
public function eat() {
$this->objectToEat->set('health',0); // This doesn't work!
}
}
And set the main program like so:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->set('objectToEat',$apple);
$paul->eat();
?>
How can I access the object's properties from inside a method? I know I use $this->objectToEat to tell PHP I'm talking about the class properity, but since that property is an object, how do I access the object's methods?
I've tried $this->objectToEat->set('health',0) but that doesn't work. I hope you guys understand what I'm trying to get at (sorry, I can't figure out how to condense my question without compromising clarity)!
You have to set the property correctly. Since it's private, you can't do this from outside the object, so you have to use encapsulation:
class Eaters {
private $name;
private $objectToEat;
public function eat() {
$this->objectToEat->set('health',0); // Assumed "object" was just a typo
}
public function setObjectToEat($object) {
$this->objectToEat = $object;
}
}
Then use it like so:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->setObjectToEat($apple);
$paul->eat();
?>
Note: In this brief example, your original method is a better design. In certain cases, you might want to prime the method to be used by setting properties beforehand, but more often you want to call it with parameters directly, since it's more clear and more reusable (compartmentalized).
This answer modifies Renesis' answer
In the class, the object to eat is a private variable hence you can't go
$paul->objectToEat = $apple;
What you can do is to make a setter method inside Eaters
class Eaters {
private $name;
private $objectToEat;
public function eat() {
$this->objectToEat->set('health',0); // Assumed "object" was just a typo
}
public function setFood($object) {
$this->objectToEat = $object;
}
}
Therefore, you can call the setFood() method instead.
OR
Change eat() to
public function eat($object) {
$this->object->set('health',0);
return $object;
}
Saving the modified object back to the original variable.
OR
class Eaters {
private $name;
public function eat(&$object) { // this passes object by reference
$object->set('health', 0);
}
}
Although this code is not tested, that is how you can pass a variable by reference.
NOTE: You only need the & when defining the method not when you're passing an argument. For more info about Passing by Reference go to this link
It's probably because your eat method isn't accepting any parameters, and the Eaters class has no $object property.
Can you make $objectToEat a reference and then use it as such in the eat() function?
you have to set $this->object in class Eaters
function __construct($object){
$this->object = $object;
}
or
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->eat($apple);
?>
class Tester {
private $variable;
private $anObj;
public function testFn($val) {
$this->variable = $val;
$this->anObj = new SecondObj();
$this->doSomething();
}
public function doSomething() {
echo("My variable is set to " . $this->variable);
$this->anObj->wow();
}
}
class SecondObj {
public function __construct() {
echo("I'm new!");
}
public function wow() { echo("Wow!"); }
}
$tester = new Tester();
$tester->testFn(42);
Output:
I'm new!My variable is set to 42Wow!