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();
?>
Related
This question already has answers here:
PHP - How to solve error "using $this when not in object context"?
(2 answers)
PHP Fatal error: Using $this when not in object context
(9 answers)
Closed 1 year ago.
I have a class which implements an interface.
interface Animal {
public static function giveHug();
}
class Dog() implements Animal {
protected $race;
public function __construct($race)
{
$this->race = $race;
}
public static function giveHug()
{
return 'Kiss my friend' . $this->race;
}
}
I get
cannot use $this in non object context.
And I understand that, so how could I get Dog property in my redefined giveHug method ?
Do someone have any trick to help?
Thanks
You need to change code either way.
If ::giveHug MUST be static, then you need to be able to provide the Animal to be hugged.
So this works:
but is not so nice
interface Animal
{
public static function giveHug(Animal $animal);
}
class Dog implements Animal
{
protected $race;
public function __construct($race)
{
$this->race = $race;
}
public static function giveHug(Animal $animal)
{
return 'Kiss my friend ' . $animal->race;
}
}
$dog = new Dog('WauWau');
echo Dog::giveHug($dog) . PHP_EOL;
// Kiss my friend WauWau
This is better:
interface Animal
{
public static function getRace();
public static function giveHug(Animal $animal);
}
class Dog implements Animal
{
protected static $race;
public function __construct($race)
{
self::$race = $race;
}
public static function getRace()
{
return self::$race;
}
public static function giveHug(Animal $animal)
{
return 'Kiss my friend ' . $animal::getRace();
}
}
$dog = new Dog('WauWau');
echo Dog::giveHug($dog) . PHP_EOL;
// Kiss my friend WauWau
BUT now to the topic: does it make sense?
No.
And this is a really good example.
You do not tell a "static" animal (or dog) to give a hug.
You would want to tell a specific (object) animal to give a hug.
So this makes more sense:
interface Animal
{
public function giveHug();
}
class Dog implements Animal
{
protected $race;
public function __construct($race)
{
$this->race = $race;
}
public function giveHug()
{
return 'Kiss my friend ' . $this->race;
}
}
$dog = new Dog('WauWau');
// Note: we call $dog to give hug. So the ONE dog =)
echo $dog->giveHug() . PHP_EOL;
// Kiss my friend WauWau
EDIT: the example
$dog = new Dog('WauWau');
echo Dog::giveHug($dog) . PHP_EOL;
is more like a "Hey, all Dogs out there ... give a hug to this (Animal $dog)".
And there are cases this makes sense. But in this case - not =)
The following code does not produce the output with the name Jock. I suspect because in the class Animal the $name is private, but the construct is public so should the subclass not be able to get the $name from the construct. I do not want to make $name public.
class Animal{
private $name;
public function __construct($name) {
$this->name = $name;
}
public function Greet(){
echo "Hello, I'm some sort of animal and my name is ", $this->name ;
}
}
class Dog extends Animal{
private $type;
public function __construct($name,$type) {
$this->type = $type;
parent::__construct($name);
}
public function Greet(){
echo "Hello, I'm a ", $this->type, " and my name is ", $this->name;
}
}
$dog2 = new Dog('Jock','dog');
$dog2->Greet();
You are right: delete the private variable or use protected in the first line of the class animal and you're fine.
class Animal{
protected $name; //see here!
public function __construct($name) {
$this->name = $name;
}
public function Greet(){
echo "Hello, I'm some sort of animal and my name is ".$this->name ;
}
}
$animal = new Animal("Gizmo");
$animal->greet(); //produces the desired result.
echo $animal->name; //this will throw an error - unable to access protected variable $name
$name won't be public since it is an argument used in the public constructor and is therefore confined to the scope of that function. The property name on the dog will be public however unless you use protected.
Dots are used to concat strings. However echo allows commas to output multiple expressions.
public function Greet(){
echo "Hello, I'm a ".$this->type." and my name is ".$this->name;
}
Also when using double quotes; you can put the variables inside the string:
public function Greet(){
echo "Hello, I'm a $this->type and my name is $this->name";
}
the private variable only accessed inside the same class, you need to use protected for the name variable in class Animal.
class Animal{
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function Greet(){
echo "Hello, I'm some sort of animal and my name is ", $this->name;
}
}
class Dog extends Animal{
private $type;
public function __construct($name,$type) {
$this->type = $type;
parent::__construct($name);
}
public function Greet(){
echo "Hello, I'm a ", $this->type, " and my name is ", $this->name;
}
}
$dog2 = new Dog('Jock','dog');
$dog2->Greet();
You could use setter & getter methods to help you modify and retrieve your instance variables without needing to declare them as public.
If you are using eclipse:
Right click on the class > Source > Generate Getters & Setters
which will create functions for all of your variables as so:
public String getName(){return this.name;}
public String setName(String name){this. name = name; }
You could then use these methods to access and edit your class variables
I have two classes (Model and User) but I have a problem so I have tried to explain it in a simple example :
class person
{
protected static $todo ="nothing";
public function __construct(){}
public function get_what_todo()
{
echo self::$todo;
}
}
class student extends person
{
protected static $todo ="studing";
}
$s = new student();
$s->get_what_todo(); // this will show the word (nothing)
//but I want to show the word (studing)
Please give me a solution but without writing any function in the student class I only want to make declarations there :) and thank you :)
The principle is called "late static binding", and was introduced in PHP 5.3.0; with the self keyword to access the property defined in the calling class within the inheritance tree, or static to access the property defined in the child class within that inheritance tree.
class person
{
protected static $todo ="nothing";
public function __construct(){}
public function get_what_todo()
{
echo static::$todo; // change self:: to static::
}
}
class student extends person
{
protected static $todo ="studying";
}
class teacher extends person
{
protected static $todo ="marking";
}
class guest extends person
{
}
$s = new student();
$s->get_what_todo(); // this will show the "studying" from the instantiated child class
$t = new teacher();
$t->get_what_todo(); // this will show the "marking" from the instantiated child class
$g = new guest();
$g->get_what_todo(); // this will show the "nothing" from the parent class,
// because $todo is not overriden in the child class
The reliable way to override a static variable is to do it by redeclaring it. Some people may suggest modifying it in the construct method, but I don't think that's reliable.
It won't reflect the changes until the class is constructed at least once. And of course, in class methods, don't forget to call the static variable using "static::" instead of "self::" when you want to always access the overridden variable.
Here's an example of what I mean:
The class Foo is the base class, the class Bar is changing the variable inside its constructor, and the class Baz is overriding the variable in its declaration.
class Foo
{
public static $a = "base";
}
class Bar extends Foo
{
function __construct()
{
self::$a = "overridden";
}
}
class Baz extends Foo
{
public static $a = "overridden";
}
echo 'Foo: ' . Foo::$a . '<br>';
echo 'Bar: ' . Bar::$a . '<br>';
echo 'Baz: ' . Baz::$a . '<br>';
new Bar();
echo 'Bar after instantiation: ' . Bar::$a;
This is the output from phptester.net
Foo: base
Bar: base
Baz: overridden
Bar after instantiation: overridden
As you can see, Bar's way of changing the variable isn't taking effect until after the constructor is called at least once.
EDIT: However, there is another way to edit a variable permanently and reliably: do it after the class declaration. This is especially handy if you only need to modify a variable and not completely override it, like for example an array. It feels a bit dirty, but in theory should work everytime.
class Foo
{
public static $a = [
'a' => 'a'
];
}
class Bar extends Foo
{
public static $a;
}
Bar::$a = Foo::$a;
Bar::$a['b'] = 'b';
echo 'Foo: ' . print_r(Foo::$a, true) . '<br>';
echo 'Bar: ' . print_r(Bar::$a, true) . '<br>';
This is the output from phptester.net
Foo: Array ( [a] => a )
Bar: Array ( [a] => a [b] => b )
EDIT 2: This last method also gets picked up by ReflectionClass::getStaticPropertyValue in my tests.
you can try set variable in construction
class person
{
protected static $todo = null;
public function __construct(){
self::$todo = "nothing";
}
public function get_what_todo()
{
echo self::$todo;
}
}
class student extends person
{
public function __construct() {
self::$todo = "student";
}
}
$s = new student();
$s->get_what_todo();
you can try set parent variable in construction
class person
{
protected static $todo = null;
public function __construct(){
self::$todo = "nothing";
}
public function get_what_todo()
{
echo self::$todo;
}
}
class student extends person
{
public function __construct() {
parent::$todo = "student";
}
}
$s = new student();
$s->get_what_todo();
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};
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);