Instantiation of subclass php with existing values of the main class - php

EDIT: Really sorry screwed up original example. More explanation at end.
I am new to OOP finding it useful, finding it confusing.
I have looked and I think this must be a simple question but searched on things like "instantiation of subclass php" but could find nothing on point.
I want to instantiate an object and then later instantiate the subclass. Can I "add" the subclass to the existing instance?
class Dog
{
protected $owner;
protected $color;
public function setOwner($owner)
{
$this->owner = $owner;
}
public function setColor($color)
{
$this->color = $color;
}
}
class Bulldog extends Dog
{
protected $name;
protected $typeOfTail;
... set tail....
public function setName($name)
{
$this->name = $name;
}
}
class Beagle extends Dog
{
protected $name;
protected $typeOfSpots;
... set spots ....
public function setName($name)
{
$this->name = $name;
}
}
$myDog = new Dog;
$myDog -> setOwner("Bob");
$myDog1 = new Beagle;
$myDog1 -> setName("name");
obviously that will not work but if I do
$myDog = new Beagle;
$myDog -> setName("name");
I presume that just sets the owner to NULL?
Is there a way to pull the existing values (or duplicate the values) of a class into and instance of a subclass (I suppose I could do some sort of complicated method to pull all the values in but there a lot of them ....) Is this something easy to do in PHP or am I off on a LIMB?
It is 3.30 am and I apologise if this is really dumb but I have hit a wall these last couple of days and am getting behind. This seems like it could be useful in the current project.
Clarification: This is a hypothetical example. (No dogs involved with the project.) Say we have a brown dog owned by Fred and we populate an instance of dog (pretend it is a big class with lots going on).
The next day someone says "that dog is a beagle" (ok later in the file - this is not a great example) so we want to instantiate a Beagle class with the name Suki.
What I want is an instance of Beagle that inherits the already existing dog info.
Sorry once again. Off to bed.

General solution: (in case you already know the future subclass)
Just directly create an instance of the subclass. You can use it as an instance of the superclass. But some more information of what you're trying to achieve would be useful.
So it would work like this:
class Dog
{
protected $owner;
protected $color;
public function setOwner($owner)
{
$this->owner = $owner;
}
public function setColor($color)
{
$this->color = $color;
}
}
class Beagle extends Dog
{
protected $name;
public function setName($name)
{
$this->name = $name;
}
}
$myDog = new Beagle;
// here we call two methods of the Dog superclass
$myDog->setOwner("Bob");
$myDog->setColor("brown");
// now we call a method of the subclass
$myDog->setName("SomeName");
As you can see there is no need to add the methods of the parent class to the subclass again. They will be inherited implicitly and you can just use them on instances of the subclasses as if they are defined within the subclass.
If you omit one of these method calls the property will be null, because no default value is assigned to the properties.
Specific solution: (in case you don't know the actual subclass)
If you can't create the subclass directly, create a constructor like this:
class Dog
{
protected $owner;
protected $color;
public function __construct(Dog $dog = null) {
if ($dog) {
foreach ($dog as $key => $value) {
if (property_exists($this, $key)) {
$this->{$key} = $value;
}
}
}
}
public function setOwner($owner)
{
$this->owner = $owner;
}
public function setColor($color)
{
$this->color = $color;
}
}
class Beagle extends Dog
{
protected $name;
public function setName($name)
{
$this->name = $name;
}
}
$dog = new Dog;
$dog->setOwner("Bob");
$beagle = new Beagle($dog);
$beagle->setColor("brown");
I did not test the code, so maybe there is still a bug in it, but it should get my point accross.

Parent and child classes
You can create 2 class, lets call one ParentClass and one ChildClass. This gives us:
class ParentClass
{
}
class ChildClass
{
}
As you can see, they are not linked in any way, shape or form, so, we need to extend the child class to use the parent, so we now have:
class ParentClass
{
}
class ChildClass extends ParentClass
{
}
Now the child speaks to the parent, so let's add a property to the parent, lets call it name:
class ParentClass
{
protected $name; //Protected means it's private, but accessible to children
}
class ChildClass extends ParentClass
{
}
Now let's add some functionality to the child, a getter and a setter:
class ParentClass
{
protected $name;
}
class ChildClass extends ParentClass
{
public function setName($value)
{
$this->name = $value;
}
public function getName()
{
return $this->name;
}
}
As you can see, it uses the $name from the parent, meaning it's value is available to the child, so we can do:
$childClass = new ChildClass();
$childClass->setName("My Name");
print $childClass->getName(); // prints My Name
And get a result!
Edit
Extra to show differentiation in the setters:
class Dog
{
protected $owner;
protected $color;
protected $name; // I'd put this here as all dogs have a name, right?
// Put the getters in here as all they do is return, they won't change (hopefully...)
public function getOwner()
{
return $this->owner;
}
public function getColor()
{
return $this->color;
}
public function getName()
{
return $this->name;
}
}
class Beagle extends Dog
{
public function setOwner($val)
{
$this->owner = $val;
}
public function setColor($val)
{
$this->color = $val;
}
public function setName($val)
{
$this->name = $val;
}
}
/**
* Added extra code to setters
*/
class Dalmatian extends Dog
{
public function setOwner($val)
{
$this->owner = "Owner: " . $val;
}
public function setColor($val)
{
$this->color = "Color: " . $val;
}
public function setName($val)
{
$this->name = "Name: " . $val;
}
}
As you can see in this example, there are 2 child classes, Beagle and Dalmatian, each with somewhat different setters for the values.
As the values are not static in the parent class, they will be different in each child, so setting one won't change the other and vica versa.
To keep values from the parent across all subclasses, use static properties as such:
class Dog
{
protected static $owner;
protected static $color; // Don't know why you'd want this kept, but okay?
}
And call using static::${variable_name}; as opposed to: $this->{variable_name};

Related

static property sharing/defining between children in PHP classes

I'm facing a misunderstanding about what the title describe and i'd like to know if there is another way to achieve what I'm looking for there.
I have an abstract class which declare a static property without value, and I instanciate subclasses from it that are defining the value of that static property. The base class also define another static property value depending of the first one, but the problem is subclasses are losing their first property value for the last one defined in other subclasses and then this second property get the bad value from the parent class.
This code demonstrate it better than I explain:
abstract class A
{
protected static $name;
protected static $path;
public function __construct()
{
static::$path = static::$name."Path";
}
public function getPath()
{
return static::$path;
}
}
class B extends A
{
protected static $name = "B";
}
class C extends A
{
protected static $name = "C";
}
$b = new B();
$c = new C();
echo $b->getPath();
I expected the echo to print "Bpath", but unfortunately it prints "CPath".
If I comment the line that instanciate the C class, then the print is good.
EDIT:
The thing is if i do this code :
abstract class A
{
protected static $name;
protected static $path;
public function __construct()
{
static::$path = static::$name."Path";
}
public function getPath()
{
return static::$path;
}
public function getName()
{
return static::$name;
}
}
class B extends A
{
protected static $name = "B";
}
class C extends A
{
protected static $name = "C";
}
$b = new B();
$c = new C();
echo $b->getName();
The name printed is "B" and good. So the fact of redefining value in subclass property doesn't have the same consequence of doing it in constructor, even if using static:: keyword.
The static property $path is only defined once on class A. Setting static::$path from anywhere will always set A::$path, so the value is shared among all classes.
You'd see a different result if you declared protected static $path; on both child classes, e.g.:
class B extends A {
protected static $name = "B";
protected static $path;
}
Now each class would have its own static $path property and they could be set independently.
It would make much more sense to use an instance property though instead of this bending over backwards with static properties:
abstract class A {
protected static $name;
protected $path;
public function __construct() {
$this->path = static::$name . 'Path';
}
public function getPath() {
return $this->path;
}
}

PHP Class Inheritance private property construct

Im taking a 3rd year module on webDesign focusing on OOP concepts which im struggling to master, but slowly getting there...
An Assignment Question Reads As Follows:
I coded thequestions above and I got the correct output but:
I am unsure if the way I coded the greet() method in question A & B is correct?
2.The constructor and related properties inside the sub class for question B, I have my doubts whether those are correctly coded...even though I'm getting correct output, Please see comments in code
I fail to see the benefit of extending the class, perhaps I don't see it because I Went about it the wrong way..?
Any advice appreciated, code follow below.
A)
class Animal{
private $name;
public function __construct($dogName){
$this->name = $dogName;
}//construct
public function greet(){
$sting = "Hello I'm some sort of animal and my name is .$this->name.";
return $sting;
}//function
}//class
$animal = new Animal('Jock');
echo $animal->greet();
B - SubClass
class Dog extends Animal
{
private $animalType;
public function __construct($animalType, $dogName){
$this->$animalType = $animalType;
$this->dogName = $dogName; //IS THIS LINE CORRECT, IF YES WHY SHOULD I USE IT AGAIN IN PARENT::_CONSTRUCT?
//Call Animal Constructor To Finish
parent::__construct($dogName);
}//constructor
public function greet($value1, $value2){
$this->animalType = $value1;
$this->dogName = $value2;
$string = "Hello, I'm a ". $value1. " and my name is ". $value2;
return $string;
}
}
$dog = new Dog('Dog', 'Jock');
echo $dog->greet('Dog', 'Jock');
Problems with your code:
1) Why would you have Dog::$animalType field? The purpose of extending generic Animal class is to make it rather specific with Dog subclass. Instead, just use strtolower(__CLASS__) for animal type.
2)Dog::greet() method doesn't need any arguments. It can clearly use $this->dogName.
3) You should name both name fields as Animal::$name and Dog::$name. That way, the sub-class will inherit from its parent class and override the values. Instead you have introduced additional field which does the same thing, and breaks the logical relation between parent and child classes.
4) Both parent and child classes should have same signatures for methods with the same name, so that inheritance could have a purpose. And since child classes inherit parent's classes as they are, there is no need to re-define them (in your case, the constructor).
class Animal
{
private $name; // can't be private (unless you use a getter), if you want to extend it
public function __construct($name)
{
$this->name = $name;
}
public function greet()
{
return "Hello I'm some sort of animal and my name is " . $this->getName();
}
protected function getName()
{
return $this->name;
}
}
class Dog extends Animal
{
public function greet()
{
return "Hello, I'm a " . strtolower(__CLASS__) . " and my name is " . $this->getName();
}
}
$animal = new Animal('Cow');
echo $animal->greet();
$dog = new Dog('Max');
echo $dog->greet();
I think that the question is worded slightly incorrectly. I think that it wants you make the properties protected rather than private to extend the class (otherwise you would have to re-define the same properties in the subclass).
If this is the case, here is an example that shows class inheritance:
class Animal
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function greet()
{
return "Hello I'm some sort of animal and my name is {$this->name}.";
}
}
$animal = new Animal('Jock');
echo $animal->greet();
class Dog extends Animal
{
public function greet()
{
return "Hello I'm a dog and my name is {$this->name}.";
}
}
$dog = new Dog('Jock');
echo $dog->greet();
You can see that we don't need to redefine the property $name and the constructor. The class Dog knows it's a dog, so we don't need to tell it that - we just adjust our greet method accordingly. This shows how we can access the protected property $name from Dog, and shows how we have overridden the greet method in Dog.
I hope this sheds some light on the subject.
I think you don't need the constructer in Dog class. The greet function looks wrong. I think you have to use the name from Animal class by using a name getter (getName).
class Animal
{
private $name;
public function __construct($name)
{
$this->name = $name;
}//construct
public function greet()
{
$sting = "Hello I'm some sort of animal and my name is " . $this->getName();
return $sting;
}//function
public function getName() {
return $this->name;
}
}//class
$animal = new Animal('Jock');
echo $animal->greet();
class Dog extends Animal
{
public function greet()
{
$string = "Hello, I'm a dog and my name is " . $this->getName();
return $string;
}
}
$dog = new Dog('Jock');
echo $dog->greet();
Another way of doing this
<?php
class Animal{
protected $name;
public function __construct($dogName){
$this->name = $dogName;
}//construct
public function greet(){
$sting = "Hello I'm some sort of animal and my name is .$this->name.";
return $sting;
}//function
}//class
$animal = new Animal('Jock');
echo $animal->greet();
class Dog extends Animal
{
private $animalType;
public function __construct($animalType,$dogname){
$this->animalType = $animalType;
parent::__construct($dogname);
}
public function greet(){
echo "Hello, I'm a ".$this->animalType. " and my name is ".$this->name;
}
}
$dog = new Dog('Dog', 'New Dog');
echo $dog->greet();
?>

Calling to a member function on a non-object Error

i'm having a trouble at the moment that i'm trying to access from a method of Wolf class to other method of Dog class. That's the code:
index.php
require_once 'Wolf.php';
require_once 'Dog.php';
class StackOverflowExample{
public static function run(){
$dog = new Dog("Cokey");
$wolf = new Wolf("Wolfenstein");
$wolf->hunt();
}
}
StackOverflowExample::run();
Wolf.php
class Wolf {
private $_name;
public function __construct($name){
$this->_name = $name;
}
public function hunt(){
return $dog->setLife(0);
}
}
Dog.php
class Dog {
private $_name;
private $_life= 100;
public function __construct($name){
$this->_name = $name;
}
public function setLife($life){
$this->_life = $life;
}
public function getLife(){
return $this->_life;
}
}
It gives me the next errors:
· Undefined variable: dog
· Call to a member function setLife() on a non-object
I have spent two days searching and I still having no way to fix.
Thanks you and sorry for my bad english.
What you should do is to pass $dog around, in the hunt method, like this:
public function hunt(Dog $dog){
return $dog->setLife(0);
}
You get the ability to validate that the dog variable is an instance of the expected class.
This method of passing objects around is called dependency injection.
If you want to pass around all sorts of animals you need to use another concept called inheritance:
abstract class Animal
{
public $_life;
public function setLife($life){
$this->_life = $life;
}
public function getLife(){
return $this->_life;
}
}
class Dog extends Animal
{
private $_name;
public function __construct($name){
$this->_name = $name;
}
}
class Wolf {
private $_name;
public function __construct($name){
$this->_name = $name;
}
public function hunt(Animal $animal){
return $animal->setLife(0);
}
}
Notice that the common methods and variables live in the parent class, and that you can create as many types as animals as you want.
If you follow this example you should find a way to declare the animal's name variable in the Animal class so you don't have to redefine it in all subclasses ;)
Replace
$dog->setLife(0);
by
Dog::setLife(0);

"Cannot access protected property" Error

I have two classes involving composition not inheritance., class A and class B. One of class A's properties is an array of class B objects. Class A has a public method A::getName(). Class B also has a public method with the same name. The method for class A is as follows:
public function getName()
{
return $this->_name;
}
My problem is when I'm in Class B and I try to access this public method for class A, I get the "cannot access protected property" error. $_name is a private property in each class. Class A's would be the name, for example, of a form, and for B, the name of the field.
This is the code that generates the error (constructor for class B):
public function __construct($name)
{
$this->foo = A::getName() .'-'. $name;
}
Why is it not allowing me to access class A's public method getName()? Any way to fix or get around this?
FIX:
I realized I was invoking class A's method statically, though I need to deal with each object individually, as each object has a unique name. To solve my issue I gave a public set function for class B for the unique name, and called that in class A:
class A
{
...
$this->list[$B_name] = new B($B_name);
$this->list[$B_name]->setID($this->_name, $B_name);
}
class B
{
...
public function setID($name, $subName)
{
$this->foo = $name .'-'. $subName;
}
This is because of you are trying to call it statically and in that method you are accessing instance variable.
it could work like this:
class A {
private static $_name = "A";
public static function getName() {
return self::$_name;
}
}
class B {
public function __construct($name) {
$this->foo = A::getName() .'-'. $name;
}
}
or this way (this is imho your situation)
class A {
private $_name;
public function __construct($name) {
$this->_name = $name;
}
public function getName() {
return $this->_name;
}
}
class B {
public function __construct($name, A $parent) {
$this->foo = $parent->getName() .'-'. $name;
}
}

PHP Accessing Parent Class Variable

class A {
private $aa;
protected $bb = 'parent bb';
function __construct($arg) {
//do something..
}
private function parentmethod($arg2) {
//do something..
}
}
class B extends A {
function __construct($arg) {
parent::__construct($arg);
}
function childfunction() {
echo parent::$bb; //Fatal error: Undefined class constant 'bb'
}
}
$test = new B($some);
$test->childfunction();
Question:
How do I display parent variable in child?
expected result will echo 'parent bb'
echo $this->bb;
The variable is inherited and is not private, so it is a part of the current object.
Here is additional information in response to your request for more information about using parent:::
Use parent:: when you want add extra functionality to a method from the parent class. For example, imagine an Airplane class:
class Airplane {
private $pilot;
public function __construct( $pilot ) {
$this->pilot = $pilot;
}
}
Now suppose we want to create a new type of Airplane that also has a navigator. You can extend the __construct() method to add the new functionality, but still make use of the functionality offered by the parent:
class Bomber extends Airplane {
private $navigator;
public function __construct( $pilot, $navigator ) {
$this->navigator = $navigator;
parent::__construct( $pilot ); // Assigns $pilot to $this->pilot
}
}
In this way, you can follow the DRY principle of development but still provide all of the functionality you desire.
Just echo it since it's inherited
echo $this->bb;
With parent::$bb; you try to retrieve the static constant defined with the value of $bb.
Instead, do:
echo $this->bb;
Note: you don't need to call parent::_construct if B is the only class that calls it. Simply don't declare __construct in B class.
class A {
private $aa;
protected $bb = 'parent bb';
function __construct($arg) {
//do something..
}
private function parentmethod($arg2) {
//do something..
}
}
class B extends A {
function __construct($arg) {
parent::__construct($arg);
}
function childfunction() {
echo parent::$this->bb; //works by M
}
}
$test = new B($some);
$test->childfunction();`
$bb has now become the member of class B after extending class A.
So you access $bb like it's an attribute of class B.
class A {
private $aa;
protected $bb = 'parent bb';
function __construct($arg) {
//do something..
}
private function parentmethod($arg2) {
//do something..
}
}
class B extends A {
function __construct($arg) {
parent::__construct($arg);
}
function childfunction() {
echo $this->bb;
}
}
$test = new B($some);
$test->childfunction();
all the properties and methods of the parent class is inherited in the child class so theoretically you can access them in the child class but beware using the protected keyword in your class because it throws a fatal error when used in the child class.
as mentioned in php.net
The visibility of a property or method
can be defined by prefixing the
declaration with the keywords public,
protected or private. Class members
declared public can be accessed
everywhere. Members declared protected
can be accessed only within the class
itself and by inherited and parent
classes. Members declared as private
may only be accessed by the class that
defines the member.
PHP Accessing Parent Class Protected Variable & Methods
class A {
protected $bb = 'parent bb';
protected function sayHello(){
echo 'Say Hello';
}
}
class B extends A {
public function childfunction() {
echo $this->bb.'<br>';
echo $this->sayHello();
}
}
$test = new B();
$test->childfunction();
Through parent class contructor you can pass data to parent class from child class. Have a look below example for better understanding
<?php
class Student
{
public $name;
function __construct($name){
$this->name = $name;
}
}
class Test extends Student
{
public $age;
function __construct($name,$age){
$this->age = $age;
parent::__construct($name);
}
}
$obj = new Test("sajib khan" ,21);
echo $obj->name;
echo $obj->age;
?>
class A {
private $points = 100;
public function getPoints() {
return $this->points;
}
}
class B extends A {
protected $points = 70;
public function getPoints() {
return parent::getPoints();
}
}
$element = new B();
echo $element->getPoints();
change the visibility private or protected for test

Categories