i wanna store some configuration data in some objects, and i've a problem...
class B {
const attr1 = 'something1';
const attr2 = 'something2';
const attr3 = 'something3';
}
class A {
const attr1 = 'somethingA1';
const attr2 = 'somethingA2';
const attr3 = 'somethingA3';
const b = <---- i wanna put here a reference of B, but B as a class (not an object...), i'm crazy?
}
I'm not sure if my example is clear... from A, i want to access to attr1 of B, like A::B::attr1, or something like this, there's another way to do this? Or i'm wrong?
There is no way to assign reference to a Class, nor is there a way to assign class constants at runtime. So your entire approach is pretty much impossible. What you can do is
const b = 'B'
and as of PHP 5.3.0 you could then do
$b = A::b;
echo $b::attr1;
but you cannot do A::b::attr1. This will raise a T_PAAMAYIM_NEKUDOTAYIM error. It's a parser limitation. PHP cannot do this as of this writing.
Because the class B contains a group of data of A, i want to store in b (of A) a complex data, i want to do like this because i wanna keep the code clean
You can solve this easily by making B a composite of A, e.g. you either inject B into A when you create A
class A
{
private $b;
public function __construct(B $b)
{
$this->b = $b;
}
}
$a = new A(new B);
or create B inside A, e.g.
class A
{
private $b;
public function __construct()
{
$this->b = new B;
}
}
Because B is just the data parts of A, you tunnel all public access through A instead of getting hold of B and then using B's methods. So any code using A does not need to know there is some B inside A. This will allow you to change B easily without needing to worry about code that consumes A, e.g. to get attr1 you add a getter to A:
public function getAttr1()
{
$b = $this->b;
return $b::attr1;
}
You can mitigate the clumsy need for assignment when using properties instead of constants in B (constants are stupid in PHP anyway as you have to treat them as public API), e.g.
class B
{
private $attr1;
public function getAttr1()
{
return $this->attr1;
}
}
And then you can do in A:
public function getAttr1()
{
return $this->b->getAttr1();
}
Even better would be not to expose the internals of B through A altogether though and only add public methods that do something with A. This will make your API much smaller and your code more OO.
You cannot reference to a class like that, because the only way you will ever use the class is through an object, so there is no point trying to do that either.
User this:
class A {
const attr1 = 'somethingA1';
const attr2 = 'somethingA2';
const attr3 = 'somethingA3';
public $b;
function __construct() {
$this -> b = new b();
}
You can simply say b = "B" ..
and if you want to create object of B , You can do new b or access the properties
Related
I have the following code:
class A {
protected $v = 'a';
public function f() {
echo 'f in A: ('.get_class($this).', '.$this->v.')<br/>';
}
}
class B extends A {
protected $v = 'b';
public function f() {
echo 'f in B: ('.get_class($this).', '.$this->v.')<br/>';
call_user_func(array($this, 'parent::f'));
}
}
class C extends B {
protected $v = 'c';
}
$a = new A();
$b = new B();
$c = new C();
$a->f();
$b->f();
$c->f();
My expected output is:
f in A: (A, a)
f in B: (B, b)
f in A: (B, b)
f in B: (C, c)
f in A: (C, c)
But what I get is an infinite loop at the end. After a bit of research, someone pointed to me that call_user_function(array($this, 'parent::f')) calls B::f when used in C.
From, there I found 3 options that work, but I do not know which one is the « good » way of doing it. Which one of the three following methods is the « correct » way?
// Option 1, explicit specification of the parent class
call_user_func(array($this, 'A::f')) ;
// Option 2, use of __CLASS__ instead of $this
call_user_func(array(__CLASS__, 'parent::f')) ;
// Option 3, combination of both options 1 and 2
call_user_func(array(__CLASS__, 'A::f')) ;
You've correctly identified that this code:
call_user_func (array($this, 'parent::f'));
When run in the context of C will keep calling B::f because $this will always be an instance of C and the parent of C is always B.
To fix it you can simple do:
call_user_func('parent::f');
It has no reference to the calling class, so it will resolve the parent class properly.
Out of the working alternative you have provided, the following is the better one:
call_user_func (array(__CLASS__, 'parent::f'));
This is because __CLASS__ always refers to the class declaration in which it appears and so will always be B.
This is the scenario:
There are 3 classes: class A, class B , class C
//A.php
class A {
public $something1;
public $something2;
//long list....
// i am the base class
}
//B.php
class B extends A {
// i am a child of A
}
//C.php
class C extends A{
// i do the side work
}
The program makes an object and sets values for class B like this:
$b = new B();
$b->something1 = "XYZ";
$b->something2 = "ABC";
...... long list.....
Now what I want is:
I want to call some functions of class C in class B.
I know I can do that by making an object in class B like this $c = new C();.
But I also want to pass all the variables of B i.e. (something1, something2 ....)
passed by the program to class C
I know I can do this like this:
$c->something1 = $this->something1;
$c->something2 = $this->something2 .....
But is it possible to do that without the above code because
$c->somethingN will just take too many lines and i do not like repetitive code.
I just want to know if there is any other way.
I know i can do that by making an object in class B like this $c = new C();.
If this are instance members (not static), this is the way to go.
Another way would be to use static members, like this:
class A {
public static $foo;
}
class B extends A {}
class C extends A {}
# usage:
B::$foo = 'bar';
echo C::$foo; // will output 'bar'
Okay, so code which is outside my control works like this:
Class A {
function use_b($b_name) {
$this -> $b_name = new B();
}
}
Class B {
var $stuff;
}
So that the object of class B is inside of class A and class A will use a passed in name for the property name of the class B property. Class B is totally unaware of the name it has been given and really doesn't need to know. But I need to know it in order to access class B from class A.
I do have enough control over the code that I can create a property for class B and set it to the name class A has given it, if that is possible. Then I can have class B pass it's name back to my function that needs to traverse class B (currently it returns only the outer object, so I have access to class B I just don't know the name it's been given.)
If that made no sense at all, please comment and let me know.
Finding out the members of A that hold instances of B is not that hard. Try this code:
<?php
Class A {
function use_b($b_name) {
$this -> $b_name = new B();
}
}
Class B {
var $stuff;
}
$a = new A();
$a->use_b('test');
foreach(get_object_vars($a) as $key=>$val)
if(get_class($val) == 'B')
echo $key . " is the member that holds an instance of B";
Just starting out with OOP in PHP and in general. From what I have been reading so far the two seem to be synonyms. Is this the case, and if not, practically speaking when people refer to objects and classes do they generally use the terms interchangeably?
Typically one would refer to an object as an instance of a class.
So you have some class Employee.
class Employee {
var $name;
function get_name ( ) { return $this->name; }
function set_name ($new_name) { $this->name = $new_name; }
}
And you declare an instance of it like:
$assistant = new Employee();
Employee is a class. $assistant is an object, that is an instance of the Employee class.
So to answer your question - a class is not an object. You create an object when you instantiate a class.
objects and classes do they generally use the terms interchangeably?
No. As in other OOP languages, classes are like the blueprints for something, say a house. Objects are the actual house after it's built. Very different things indeed.
// blueprint
class House
{
public $color;
public function __construct($color = 'red')
{
$this->color = $color;
}
}
// make red house
$redHouse = new House();
// make blue house
$blueHouse = new House('blue');
// Now we have two different houses (objects) made from the same blueprint (class)
They're certainly not synonymous, and if you've been reading that, it's time to change the book! :-)
Classes are types, while objects are instances.
A simple example is an integer. "Integer" denotes the type, but an integer $x is an instance of that type. In PHP there isn't a strong type system, so this may not be entirely apparent, but I hope you get the idea. Similarly, array is a type, but $v = array(); creates an instance (called $v) of array type.
With classes, you cannot just say $y = MyClass(); as you do with arrays, instead, you have to use new: $y = new MyClass();.
A class is a definition of an object. An object is an instance of a class. For example:
class Parser {
public function parse() {}
}
...is a class. You might say "The Parser class can be used to parse text."
$p = new Parser;
Now, $p is an object. It is an instance of the Parser class.
This is particularly important with the static keyword. Static methods and members belong to classes, not objects.
class Parser {
public static $type;
public $text;
}
$p1 = new Parser;
$p2 = new Parser;
$p1::$type = 'php';
$p1->text = 'sometext';
$p2->text = 'someothertext';
echo $p2::$type; //echos "php"
echo $p1->text; //echos "sometext"
You can remove the in php from your question and it is still the same thing.
A class defines an Object for example
class Person {
}
is a class that defines an person object.
The distinction get more important when you start creating class methods and object methods
class Person {
function hair_color(color) {
hair_color = color;
}
}
is an object method in php you could do something like this
austin = new Person()
austin -> hair_color("brown")
now you can have something like
class Person {
total = 0;
static function total_in_class() {
total++;
}
}
now that is an class method it affects all objects of the same class
that way
austin = new Person();
austin -> total_in_class
tom = new Person();
echo tom->total
Now if my php isn't that rusty then it should echo 1. That is because all objects in the class are affected
In ruby it would look as follows
class Person
def hair_color(color)
hair_color = color;
end
def self.total_in_class()
total+=1
end
end
Similar and same concepts apply
Specifically, is one more efficient than the other?
There is at leat two differences between forward_static_call_array and call_user_func_array :
The first one only exists since PHP 5.3
The first one must be called from inside a class
After that, I suppose there is some difference that's related to Late Static Binding, that was introduced with PHP 5.3.
Actually, if you take a closer look at the given example, it seems to be exactly that : the "context" of the class inside which you are using forward_static_call_array is "kept", in the called method.
Considering this portion of code, that's derived from the given example :
class A {
const NAME = 'A';
public static function test() {
$args = func_get_args();
echo static::NAME, " ".join(',', $args)." \n"; // Will echo B
}
}
class B extends A {
const NAME = 'B';
public static function test() {
echo self::NAME, "\n"; // B
forward_static_call_array(array('A', 'test'), array('more', 'args'));
}
}
B::test('foo');
You'll get this output :
B
B more,args
i.e. from the method in class A, you "know", via the static:: keyword, that you're "coming from B".
Now, if you try to do the the same thing with call_user_func :
class B extends A {
const NAME = 'B';
public static function test() {
echo self::NAME, "\n"; // B
call_user_func_array(array('A', 'test'), array('more', 'args'));
}
}
(the rest of the code doesn't change)
You'll get this output :
B
A more,args
Note the A on the second line ! With forward_static_call_array, you didn't get an A, but a B.
That's the difference : forward_static_call_array forwards the static context to the method that's called, while call_user_func_array doesn't.
About your efficiency question : I have no idea -- you'd have to benchmark ; but that's really not the point : the point is that those two functions don't do the same thing.