Referencing the same variable across two different classes - php

<?php
class Foo{
public $basket;
public function __construct()
{
$this->basket = 1;
}
public function getBasket(){
return $this->basket;
}
}
class Bar{
public function __construct(&$basket)
{
$basket++;
}
}
$newFoo = new Foo();
$newBar = new Bar($newFoo->getBasket());
echo $newFoo->getBasket();
?>
I am hoping to initialise the $basket value in one class and manipulate the same variable via another class. Unfortunately, I keep getting the "Notice: Only variables should be passed by reference in " error message.
Question: How can I change the code to make this happen? Thank you.

Change
$newBar = new Bar($newFoo->getBasket());
To
$basket = $newFoo->getBasket();
$newBar = new Bar($basket);
The first way doesn't work because PHP doesn't have any variable with which to hold the value you're passing to new Bar() As a consequence, nothing can be passed by reference.
The second way works because the $basket var is a fixed reference in memory, so it can be passed by reference to new Bar()
You asked in comments:
have changed my code to yours. echo $newFoo->getBasket(); produces 1
(I was hoping for 2).
1 is produced because each call to getBasket() gives you a fresh copy of the class variable. The $basket that I passed to new Bar() equals 2, but that's not what you're echoing.
If you want the result of getBasket() and the variable $basket to refer to the same reference in memory, you need to make two changes:
1 Change the function declaration to:
public function &getBasket()
2 Change how you store the function result to:
$basket = &$newFoo->getBasket();
Now your echo will return 2 because you would have a unique basket reference throughout your code
See the docs

Related

What is the difference in this way of method calling

As I got it, in the first example an object is created, and in the second one I don't see an object created. I am trying to understand, what is the difference between the two ways of method calling :
<?php
class Animal{
public $voice;
public function speak($sound){
echo $this->voice = $sound;
}
}
// Example 1
$tiger = new Animal();
$tiger->speak('Roar');
// Example 2
(new Animal)->speak("Cloak Cloak");
Whenever you use "new", you're creating an instance of an object (it can be temporary). The difference in your code is that in the first example, you're storing the instance in "$tiger", so it'll persist, but in the second example you're only instantiating a temporary object to call a method.
In the first example, you are assigning the variable $tiger as a new Object, by which you can then call the functions and variables associated with that object, by referencing $tiger.
i.e. as Tiger now equals an Object of Class Animal, it can speak.
However in the second example, you are still creating a new Object of class Animal, and as such it can speak - but you have not assigned it to a variable. So you cannot reference that same Object any longer.
So in the first example, if we wanted to name our $tiger, we could have the Class look something like this.
class Animal{
public $voice;
public $name = "I have no name.";
public function speak($sound){
echo $this->voice = $sound;
}
public function sayYourName(){
echo $this->name;
}
}
Now if we say,
$tiger = new Animal();
$tiger->speak('Roar');
$tiger->name = "Rory";
$tiger->sayYourName(); // This will echo "Rory"
However, if you try your second example instead :
(new Animal)->sayYourName(); // This will echo "I have no name."
So if you say :
(new Animal)->name = "Rory";
(new Animal)->sayYourName(); // This will still echo "I have no name".
This is because we haven't assigned a reference to the new animal, so while we can access methods of the function, and even predefined variables, we can't then reference them again later on.
To do that, we should stick to the first method (i.e. referencing)
$tiger = new Animal();
$tiger->name = "Rory";
$tiger->sayYourName();
In conclusion, use referencing to refer to an Object later on. i.e to get the animals attention, you have to call it by its name.

How can I make an array of type "class" in PHP?

I have the following class with several properties and a method in PHP (This is simplified code).
class Member{
public $Name;
public $Family;
public function Fetch_Name(){
for($i=0;$i<10;$i++){
$this[$i]->$Name = I find the name using RegExp and return the value to be stored here;
$this[$i]->Family = I find the family using RegExp and return the value to be stored here;
}
}//function
}//class
In the function Fetch_Name(), I want to find all the names and families that is in a text file using RegExp and store them as properties of object in the form of an array. But I don't know how should I define an array of the Member. Is it logical or I should define StdClass or 2-dimension array instead of class?
I found slightly similar discussion here, but a 2 dimensional array is used instead of storing data in the object using class properties.
I think my problem is in defining the following lines of code.
$Member = new Member();
$Member->Fetch_name();
The member that I have defined is not an array. If I do define it array, still it does not work. I did this
$Member[]= new Member();
But it gives error
Fatal error: Call to a member function Fetch_name() on a non-object in
if I give $Member[0]= new Member() then I don't know how to make $Member1 or Member[2] or so forth in the Fetch_Name function. I hope my question is not complex and illogical.
Many thanks in advance
A Member object represents one member. You're trying to overload it to represent or handle many members, which doesn't really make sense. In the end you'll want to end up with an array that holds many Member instances, not the other way around:
$members = array();
for (...) {
$members[] = new Member($name, $family);
}
Most likely you don't really need your Member class to do anything really; the extraction logic should reside outside of the Member class, perhaps in an Extractor class or something similar. From the outside, your code should likely look like this:
$parser = new TextFileParser('my_file.txt');
$members = $parser->extractMembers();
I think you should have two classes :
The first one, Fetcher (or call it as you like), with your function.
The second one, Member, with the properties Name and Family.
It is not the job of a Member to fetch in your text, that's why I would make another class.
In your function, do your job, and in the loop, do this :
for($i = 0; $i < 10; ++$i){
$member = new Member();
$member->setName($name);
$member->setFamily($family);
// The following is an example, do what you want with the generated Member
$this->members[$i] = $member;
}
The problem here is that you are not using the object of type Member as array correctly. The correct format of your code would be:
class Member{
public $Name;
public $Family;
public function Fetch_Name(){
for($i=0;$i<10;$i++){
$this->Name[$i] = 'I find the name using RegExp and return the value to be stored here';
$this->Family[$i] = 'I find the family using RegExp and return the value to be stored here';
}
}
}
First, $this->Name not $this->$Name because Name is already declared as a member variable and $this->Name[$i] is the correct syntax because $this reference to the current object, it cannot be converted to array, as itself. The array must be contained in the member variable.
L.E: I might add that You are not writing your code according to PHP naming standards. This does not affect your functionality, but it is good practice to write your code in the standard way. After all, there is a purpose of having a standard.
Here you have a guide on how to do that.
And I would write your code like this:
class Member{
public $name;
public $family;
public function fetchName(){
for($i=0;$i<10;$i++){
$this->name[$i] = 'I find the name using RegExp and return the value to be stored here';
$this->family[$i] = 'I find the family using RegExp and return the value to be stored here';
}
}
}
L.E2: Seeing what you comented above, I will modify my answer like this:
So you are saying that you have an object of which values must be stored into an array, after the call. Well, after is the key word here:
Initialize your object var:
$member = new Memeber();
$memebr->fechNames();
Initialize and array in foreach
$Member = new Member();
foreach ($Member->Name as $member_name){
$array['names'][] = $member_name;
}
foreach ($Member->Family as $member_family) {
$array['family'][] = $member_family;
}
var_dump($array);
Is this more of what you wanted?
Hope it helps!
Keep on coding!
Ares.

PHP combine $this variable

How to combine two variables to obtain / create new variable?
public $show_diary = 'my';
private my_diary(){
return 1;
}
public view_diary(){
return ${"this->"}.$this->show_diary.{"_diary()"}; // 1
return $this->.{"$this->show_diary"}._diary() // 2
}
both return nothing.
Your class should be like following:
class Test
{
public $show_diary;
function __construct()
{
$this->show_diary = "my";
}
private function my_diary(){
return 707;
}
public function view_diary(){
echo $this->{$this->show_diary."_diary"}(); // 707
}
}
It almost looks from your question like you are asking about how to turn simple variables into objects and then how to have one object contain another one. I could be way off, but I hope not:
So, first off, what is the differnce between an object and a simple variable? An object is really a collection of (generally) at least one property, which is sort of like a variable within it, and very often functions which do things to the properties of the object. Basically an object is like a complex variable.
In PHP, we need to first declare the strucutre of the object, this is done via a class statement, where we basicaly put the skeleton of what the object will be into place. This is done by the class statement. However, at this point, it hasn't actually been created, it is just like a plan for it when it is created later.
The creation is done via a command like:
$someVariable= new diary();
This executes so create a new variable, and lays it out with the structure, properties and functions defined in the class statement.
From then on, you can access various properties or call functions within it.
class show_diary
{
public $owner;
public function __construct()
{
$this->owner='My';
}
}
class view_diary
{
public $owner;
public $foo;
public function __construct()
{
$this->foo='bar';
$this->owner=new show_diary();
}
}
$diary= new view_diary();
print_r($diary);
The code gives us two classes. One of the classes has an instance of the other class within it.
I have used constructors, which are a special type of function that is executed each time we create a new instance of a class - basically each time we declare a variable of that type, the __construct function is called.
When the $diary= new view_diary(); code is called, it creates an instance of the view_diary class, and in doing so, the first thing it does is assigns it's own foo property to have the value 'bar' in it. Then, it sets it's owner property to be an instance of show_diary which in turn then kicks off the __construct function within the new instance. That in turn assigns the owner property of the child item to have the value 'My'.
If you want to access single properties of the object, you can do so by the following syntax:
echo $diary->foo;
To access a property of an object inside the object, you simply add more arrows:
echo $diary->owner->owner;
Like this?
$diary = $this->show_diary . '_diary';
return $this->$diary();

Is is possible to store a reference to an object method?

Assume this class code:
class Foo {
function method() {
echo 'works';
}
}
Is there any way to store a reference to the method method of a Foo instance?
I'm just experimenting and fiddling around, my goal is checking whether PHP allows to call $FooInstance->method() without writing $FooInstance-> every time. I know I could write a function wrapper for this, but I'm more interested in getting a reference to the instance method.
For example, this pseudo-code would theoretically store $foo->method in the $method variable:
$foo = new Foo();
$method = $foo->method; //Undefined property: Foo::$method
$method();
Apparently, as method is a method and I'm not calling it with () the interpreter thinks I'm looking for a property thus this doesn't work.
I've read through Returning References but the examples only show how to return references to variables, not methods.
Therefore, I've adapted my code to store an anonymous function in a variable and return it:
class Foo {
function &method() {
$fn = function() {
echo 'works';
};
return $fn;
}
}
$foo = new Foo();
$method = &$foo->method();
$method();
This works, but is rather ugly. Also, there's no neat way to call it a single time, as this seems to require storing the returned function in a variable prior to calling it: $foo->method()(); and ($foo->method())(); are syntax errors.
Also, I've tried returning the anonymous function directly without storing it in a variable, but then I get the following notice:
Notice: Only variable references should be returned by reference
Does this mean that returning/storing a reference to a class instance method is impossible/discouraged or am I overlooking something?
Update: I don't mind adding a getter if necessary, the goal is just getting a reference to the method. I've even tried:
class Foo {
var $fn = function() {
echo 'works';
};
function &method() {
return $this->fn;
}
}
But from the unexpected 'function' (T_FUNCTION) error I'd believe that PHP wisely doesn't allow properties to store functions.
I'm starting to believe that my goal isn't easily achievable without the use of ugly hacks as eval().
It is. You have to use an array, with two values: the class instance (or string of the class name if you are calling a static method) and the method name as a string. This is documented on the Callbacks Man page:
A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1.
Demo (Codepad):
<?php
class Something {
public function abc() {
echo 'called';
}
}
$some = new Something;
$meth = array($some, 'abc');
$meth(); // 'called'
Note this is also works with the built-ins that require callbacks (Codepad):
class Filter {
public function doFilter($value) {
return $value !== 3;
}
}
$filter = new Filter;
$test = array(1,2,3,4,5);
var_dump(array_filter($test, array($filter, 'doFilter'))); // 'array(1,2,4,5)'
And for static methods -- note the 'Filter' instead of an instance of a class as the first element in the array (Codepad):
class Filter {
public static function doFilter($value) {
return $value !== 3;
}
}
$test = array(1,2,3,4,5);
var_dump(array_filter($test, array('Filter', 'doFilter'))); // 'array(1,2,4,5)'
// -------- or -----------
var_dump(array_filter($test, 'Filter::doFilter')); // As of PHP 5.2.3
Yes, you can. PHP has a "callable" pseudo-type, which is, in fact, either just a string or an array. Several functions (usort comes to mind) accept a parameter of the "callback" type: in fact, they just want a function name, or an object-method pair.
That's right, strings are callable:
$fn = "strlen";
$fn("string"); // returns 6
As mentioned, it's possible to use an array as a callback, too. In that case, the first element has to be an object, and the second argument must be a method name:
$obj = new Foo();
$fn = array($obj, "method");
$fn(); // calls $obj->method()
Previously, you had to use call_user_func to call them, but syntax sugar in recent versions make it possible to perform the call straight on variables.
You can read more on the "callable" documentation page.
No, as far as I know it's not possible to store a reference to a method in PHP. Storing object / class name and a method name in an array works, but it's just an array without any special meaning. You can play with the array as you please, for example:
$ref = [new My_Class(), "x"];
// all is fine here ...
$ref();
// but this also valid, now the 'reference' points to My_Other_Class::x()
// do you expect real reference to behave like this?
$ref[0] = new My_Other_Class();
$ref();
// this is also valid syntax, but it throws fatal error
$ref[0] = 1;
$ref();
// let's assume My_Class::y() is a protected method, this won't work outside My_Class
$ref = [new My_Class(), 'y'];
$ref();
this is prone to error as you loose syntax checking due to storing the method name as string.
you can't pass reliably a reference to a private or a protected method this way (unless you call the reference from a context that already has proper access to the method).
Personally I prefer to use lambdas:
$ref = function() use($my_object) { $my_object->x(); }
If you do this from inside $my_object it gets less clunky thanks to access to $this:
$ref = function() { $this->x(); }
this works with protected / private methods
syntax checking works in IDE (less bugs)
unfortunately it's less concise

different explanation

The code
$global_obj = null;
class my_class
{
var $value;
function my_class()
{
global $global_obj;
$global_obj = &$this;
}
}
$a = new my_class;
$a->my_value = 5;
$global_obj->my_value = 10;
echo $a->my_value;
echoes 5, not 10.
"Upon first examination, it would seem that the constructor of my_class stores a reference to itself inside the $global_obj variable. Therefore, one would expect that, when we later change the value of $global_obj->my_value to 10, the corresponding value in $a would change as well. Unfortunately, the new operator does not return a reference, but a copy of the newly created object."
I still don't understand it, so can anyone please explain it differently, and help me understand?
Not sure why this is the way it works, but, if you remove the & in front of $this while assigning it to your global variable, it will work.
To illustrate that, the following portion of code :
$global_obj = null;
class my_class
{
public $my_value;
public function __construct()
{
global $global_obj;
$global_obj = $this;
}
}
$a = new my_class;
$a->my_value = 5;
$global_obj->my_value = 10;
echo $a->my_value;
Gives the following output :
10
Here are the differences with your code :
I remove the & before $this : with PHP 5, there is no need for that, when working with objects
I translated the code to real PHP 5 :
__construct for the constructor
use public/protected/private, and not var for properties
As a sidenote, the code you posted should have given you the following warning :
Strict standards: Creating default object from empty value
Notes :
I'm using PHP 5.3.2
E_ALL doesn't include E_STRICT (source)
EDIT after some more searching :
Going through the References Explained section of the PHP manual, and, more specifically the What References Do page, there is a warning given that says (quoting) :
If you assign a reference to a
variable declared global inside a
function, the reference will be
visible only inside the function. You
can avoid this by using the $GLOBALS
array.
And there is an example going with it.
Trying to use $GLOBALS in your code, I have this portion of code :
$global_obj = null;
class my_class
{
public $my_value;
public function __construct()
{
$GLOBALS['global_obj'] = & $this;
}
}
$a = new my_class;
$a->my_value = 5;
$global_obj->my_value = 10;
echo $a->my_value;
And I get the following output :
10
Which seems to work ;-)
If I replace the __construct method by this :
public function __construct()
{
global $global_obj;
$global_obj = & $this;
}
It doesn't work...
So it seems you should not use global, here, but $GLOBALS.
The explanation given in the manual is :
Think about global $var; as a
shortcut to $var =&
$GLOBALS['var'];. Thus assigning
another reference to $var only
changes the local variable's
reference.
And, just so it's said : using global variables is generally not quite a good idea -- and, in this specific situation, it feels like a very bad idea...
(Now, if this question what just to understand why... Well, I can understand your curiosity ;-) )

Categories