I'm going through some PHP question for my exam, and in the question below, apparently (B) is the answer.
What is the output of the following code?
class Magic {
public $a = 'A';
protected $b = array('a' => 'A', 'b' => 'B', 'c' => 'C');
protected $c = array(1, 2, 3);
public function __get($v) {
echo "$v,";
return $this->b[$v];
}
public function __set($var, $val) {
echo "$var: $val,";
$this->$var = $val;
}
}
$m = new Magic;
echo $m->a.','.$m->b.','.$m->c.',';
$m->c = 'CC';
echo $m->a.','.$m->b.','.$m->c;
A: A,Array,Array,A,Array,Array,CC
B: b,c,A,B,C,c: CC,b,c,A,B,C
C: a,b,c,A,B,C,c: CC,a,b,c,A,B,C
D: b,c,A,B,C,c: CC,b,c,A,B,CC
Sorry for the noob question, but coming from Java, I can't for the life of me understand why this is the correct answer.
$b and $c are a protected properties so they cannot be set from outside the class scope. $a is public so it can be set/accessed directly.
For accessing $b and $c, it will fallback to the magic getter which retrieves the values from the $b array.
The logic follows:
b, <- getter echo (executed by $m->b)
c, <- getter echo (executed by $m->c)
A, <- public property value (this is the start of the first global echo expression)
B, <- getter return b[b]
C, <- getter return b[c]
c: CC, <- setter echo, sets c = CC, but c is never accessed
b, <- getter echo (executed by $m->b)
c, <- getter echo (executed by $m->c)
A, <- public property value (this is the start of the second global echo expression)
B, <- getter return b[b]
C <- getter return b[c]
The getter echoes are processed first because their echo statements are reached before the echoed expression (with concatenation) has finished evaluating.
Since $a is public, no magic setters or getters are used.
Does this cut down version make it any clearer?
class Magic
{
public $a = "A";
protected $b = ['a' => 'A', 'b' => 'B', 'c' => 'C'];
public function __get($v)
{
echo "A MAGIC METHOD IS BEING CALLED TO GET THE PROPERTY $v", PHP_EOL;
return $this->b[$v];
}
}
$m = new Magic;
echo ($m->a . ',' . $m->b . ',' . $m->c);
A MAGIC METHOD IS BEING CALLED TO GET THE PROPERTY b
A MAGIC METHOD IS BEING CALLED TO GET THE PROPERTY c
A,B,C
I suppose the point is to demonstrate two things:
That PHP's magic __get method is only called for properties that are not directly accessible (i.e. not public). The implementation of the method can then return any string at all - in this case the property name is used to look up an element of a different array.
That variables concatenated into a string are resolved before the string is used. So the __get method is called twice (for the inaccessible properties b and c), and the echo statement inside that method is called before the string itself is concatenated and displayed.
The call to set the property c between the two "echo" lines is similarly resolved using the __set method, although it doesn't haven't any impact on the rest of the code.
Demo: https://3v4l.org/4Bitg
The apparent answer is wrong (Or you had a typo while writing it down):
B: b,c,A,B,C,c: CC,b,c,A,B,C
The sequence C,c is not possible, it has to be c,C, when accessing $m->c.
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'
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
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";
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.