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'
Related
I'm trying to work out exactly how deep inheritance goes.
For example if I start with class A
Class B extends class A
Class C extends class B
Class D extends class C
Class E extends class D
Class F extends class E
Class G extends class F
most of the lower levels are abstract classes with methods filled with code and abstract methods. its a rather large and complex structure. (doing my head in)
Will Class G still be able to access Class A methods and parameters, as well as still have access to the abstract methods from Class A ?
I'm asking because I have been having trouble with eclipse not adding the lower class methods into the auto complete. I would like to know if there is actually a limit to this or whether it's just eclipse reaching its maximum for code completion.
I'm far from a stage where I can test this with what I have done and don't want to find when I'm done that methods defined lower in the order are not accessible.
Sounds like a problem with your editor. For example, see the following quick-and-dirty demonstration:
php > class a { function foo() { echo "A::foo()\n"; } }
php > $letters = range('a', 'z');
php > for ($i = 0; $i < 25; $i++) { eval("class {$letters[$i+1]} extends {$letters[$i]} {}"); }
php > $z = new z;
php > $z->foo();
A::foo()
PHP doesn't impose any kind of restriction like this on you.
Using a canonical test like this:
<?php
abstract class A {
abstract function getValue();
}
abstract class B extends A{ }
abstract class C extends B{ }
abstract class D extends C{ }
abstract class E extends D{ }
abstract class F extends E{ }
class G extends F{
}
?>
one would expect a fatal error in that G does not in fact implement the abstract method defined in A. As you can see from the link above, this is in fact the case.
Thus, while this is a deep inheritance, it is beneath whatever limit (if any) PHP has. Rather, you're likely running into an indexer issue in the PDT.
The following php:
class A
{
public function FooA()
{
echo "A!!";
}
}
class B extends A
{
public function FooB()
{
echo "B!!";
}
}
class C extends B
{
public function FooC()
{
parent::FooB();
parent::FooA();
}
}
$test = new C();
$test->FooC();
prints:
B!!A!!
I tested this at a depth of 50 and it still functioned just fine, so you definitely can, sounds like your editor plug-in only looks so deep in the inheritance tree
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.
I have a class hierarchy in PHP 5.2.9.
The base class has a protected property which is an associative array.
The child classes can add some elements to the array.
The child classes are declared in the separate files (plugins), which will be created and added by multiple developers.
Which is the best way to add the elements to the property in the child classes so that declaring a new child would be as simple as possible?
<?php
class A {
protected $myproperty = array (
'A1' => 1,
'A2' => 2
);
function myprint()
{
print_r($this->myproperty);
}
};
class B extends A {
// add 'B1', 'B2' to myproperty
};
class C extends B {
// add 'C1', 'C2' to myproperty
};
$c = new C();
$c->myprint();
// The line above should print A1, A2, B1, B2, C1, C2
?>
Ideally, I'd like to make it for the developers as simple as declaring a variable or a private property, without having a need to copypaste any code.
Make use of the constructors of the inherited classes, for class B it would become something like this:
class B extends A {
function __construct() {
parent::__construct(); // Call constructor of parent class
array_push($myproperty, "B1", "B2"); // Add our properties
}
}
Same goes for class C.
If you have a lot of inherited classes, or want to provide as much support as possible, you could put this code into some function. So the other developers only need to call this function in their constructor to 'register' their child.