When developing in C#, and you had many classes that used the same exact code, you could rely on another class to hold the generic information, making it easier to modify these classes.
I was wondering if there was anything like that in PHP?
class Dog extends Animal {
private $animalManager
public function __construct(AnimalManager $animalManager) {
$this->animalManager = $animalManager;
}
}
class Cat extends Animal {
private $animalManager
public function __construct(AnimalManager $animalManager) {
$this->animalManager = $animalManager;
}
}
class Fish extends Animal {
private $animalManager
public function __construct(AnimalManager $animalManager) {
$this->animalManager = $animalManager;
}
}
class Animal {
// Nothing, yet...
}
What C# would allow you to do is, store the $animalManager and the constructor assignement in the 'Animal' class somehow, making it constant in 1 place if you ever needed to change it.
The thing is, PHP does this quite neatly.Every extending class inherits everything from the extended class. This means the parent's (in this case animal) construct will run whenever you call one of the extending classes.
However, you overwrite your parent's class when you call __construct() within the child. Therefore you'd need to specifically call parent::__construct() to run the parent constructor.
class Animal {
//Private vars can't be directly accessed by children.
//You'd have to create a function in the parent return it.
public $animalManager
//This function will automatically be called if you leave the
//constructor out of the extended class
public function __construct($animalManager) {
$this->animalManager = $animalManager;
}
//If you want $animalManager to be private
//Call like $fish->getAnimalManager();
//Though I do not see the use of this.
public function getAnimalManager(){
return $this->animalManager
}
}
class Fish extends Animal {
//You do not need to do this if you leave the construct out of this class
public function __construct($animalManager) {
parent::__construct($animalManager);
//Do whatever you like here
}
}
Example with only the parent constructor:
class Fish extends Animal {
//The parent's constructor is called automatically as it's not
//Being overwritten by this class
public function test(){
var_dump($this->animalManager);
}
}
Note that you would also not need to initiate the parent class seperately. Just call it like so;
$fish = new Fish(myAnimalManager);
$am = $fish->animalManager;
echo $am;
A draft has been added by Ben Scholzen for generics here.
But all I can see is type parameters and no wildcards. It supports generic functions and generic constructors. It also supports Bounds.
Unlike C# and Java, PHP will have its type arguments fully reified, which means we can reflectively know the run time parameter of desired function/constructor.
Backward compatibility is not a concern here, because type parameters and raw types can never be compatible. So the legacy code won't be compatible with Generics.
Related
I have the following classes
Abstract class duck
This class have flyBehavoir of type FlyBehavoir
Function to perform flying preformFly()
Function to set flyBehavoir setFlyBrhavoir(FlyBehavoir $flyBehavoir)
Class DonaldDuck extends Duck
in this class, I have a __construct method, inside this constructor, I instantiate new fly behavior FlyWithWings.
The problem is when I need to change flyBehavoir in the runtime via setFlyBrhavoir() method and set it to FlyWithRocket it does not change as long as flyBehavoir is private if I make it public it works fine. how can I do that?
thought that we can change any property in the superclass from the child class, as long as I access this private property vis setter.
below my attempt
<?php
//abstract class that defines what it takes to be a duck
//inside Duck we will have $flyBehavoir object of FlyBehavoir Type
abstract class Duck{
private $flyBehavoir;
public function preformFly(){
$flyBehavoir.fly();
}
public function setFlyBehavoir(FlyBehavoir $flyBehavoir){
$this->flyBehavoir = $flyBehavoir;
}
}
//creating type FlyBehavoir
interface FlyBehavoir{
function fly();
}
//this concrete class of type FlyBehavoir this will provide our ducks with the functionality they need to fly
class FlyWithWings implements FlyBehavoir{
public function fly(){
echo "I am Flying with my own Wings<br>";
}
}
//this concrete class of type FlyBehavoir this will provide our ducks with the functionality they need to fly
class FlyWithRocket implements FlyBehavoir{
public function fly(){
echo "I am the fastest duck ever, see my rockets wings <br>";
}
}
// creating our first duck and given it the ability to fly with wings
class DonaldDuck extends Duck{
public function __construct(){
$this->flyBehavoir = new FlyWithWings;
}
}
$donaldDuck = new DonaldDuck( ) ;
$donaldDuck->flyBehavoir->fly();
//changing behavoir in run time
$donaldDuck->setFlyBehavoir(new FlyWithRocket);
$donaldDuck->flyBehavoir->fly();
Output
I am Flying with my own Wings
I am Flying with my own Wings
A private property is not accessible in child classes.
class DonaldDuck extends Duck {
public function __construct(){
$this->flyBehavoir = new FlyWithWings;
}
}
For all intents and purposes, this class does not formally declare flyBehaviour at all, so $this->flyBehaviour in the constructor creates a new public property. You can see that clearly when var_dumping the object:
object(DonaldDuck)#1 (2) {
["flyBehavoir":"Duck":private]=>
NULL
["flyBehavoir"]=>
object(FlyWithWings)#2 (0) {
}
}
The parent's private property is a) separate, b) private to it and c) null since nobody has set it yet. Otherwise it would also not be possible for you to access $donaldDuck->flyBehavoir->fly() from without the class!
If you have a private property, you need to only let code of the same class act on it:
class DonaldDuck extends Duck {
public function __construct(){
$this->setFlyBehaviour(new FlyWithWings);
}
}
$donaldDuck = new DonaldDuck();
$donaldDuck->setFlyBehavoir(new FlyWithRocket);
$donaldDuck->preformFly();
This works as you expect, since you're using the correctly privileged methods to access the property. If you want to access the property directly in child classes, it needs to be protected (which then won't let you access it from outside the class though, it would have to be public for that).
In other OO languages like Java we can override a function, possible using keywords/annotations like implements, #override etc.
Is there a way to do so in PHP? I mean, for example:
class myClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
I want user to implement their own myClass::reImplementThis() method.
How can I do that in PHP? If it is possible, can I make it optional?
I mean, if the user is not implementing the method, can I specify a default method or can I identify that the method is not defined (can I do this using method_exists)?
<?php
abstract class Test
{
abstract protected function test();
protected function anotherTest() {
}
}
class TestTest extends Test
{
protected function test() {
}
}
$test = new TestTest();
?>
This way the class TestTest must override the function test.
Yes, there is. You have the option to override a method by extending the class and defining a method with the same name, function signature and access specifier (either public or protected) it had in the base class. The method should not be declared abstract in the base class or you will be required to implement it in the derived class. In you example it would look something like this:
class MyClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
class MyDerivedClass extends MyClass {
public static function reImplmentThis() { //the method you want to call
}
}
If the user does not overrides it, MyDerivedClass will still have a reImplmentThis() method, the one inherited from MyClass.
That said, you need to be very careful when invoking extended static methods from your derived class to stay out of trouble. I encourage you to refactor your code to extend instance methods unless you have a very specific need to extend static classes. And if you decide there is no better way than extending static classes please be sure to understand Late Static Binding pretty well.
Yes, its possible to check if the method is implemented or not and get a whole lot more of information about a class using PHP Reflection.
This touches on several OOP subjects.
First, simply overriding an method declared in a parent class is as simple as re-declaring the method in an inheriting class.
E.g:
class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
}
class Tommy extends Person {
public function greet(string $whom = "everyone") {
echo "Howdy $whom! How are you?";
}
}
$a = new Tommy();
$a->greet('World');
// outputs:
// Howdy World! How are you?
If on the overriding method you wan to reuse the logic of the overriden one, it's just a matter of calling the parent's method from the extending class::
class Tommy
{
public function greet(string $whom)
{
// now with more emphasis!!!
echo parent::greet(strtoupper($whom)) . "!!!!";
}
}
Now Tommy::greet() calls Person::greet(), but modifies the result before returning it.
One thing to note is that overriding methods have to be compatible with the overriden one: the method visibility can't be more restrictive than the original one (it's OK to increase visibility), and the number and type of required arguments can't conflict with the original delcaration.
This works, because the type of the arguments does not clash with the original, and we have less required arguments than on the parent:
class Leo extends Person {
public function greet(string $whom = "gorgeous", string $greet = "Whatsup" ) {
echo "$greet $whom. How are you?";
}
}
But this doesn't, since there are additional required arguments. This would make impossible to switch the original class for this one transparently, and thus would throw a Warning:
class BadBob extends Person {
public function greet(string $whom, string $greet ) {
echo "$greet $whom. How are you?";
}
}
Additionally, you mention in your question that "this method should be overriden by the user". If you require client classes to actually implement the method, you have a couple of options:
Abstract classes & methods
These are methods where the implementation is left empty, and that extending classes have to implement to be valid. In we changed our original class Person to:
abstract class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
public abstract function hide();
}
Since now the class contains an abstract method, it needs to be declared as an abstract class as well.
Now it is not possible to instantiate Person directly, you can only extend it in other classes.
Now all our existing Person extending classes would be wrong, and trying to execute the previous code would throw a fatal error.
An example of a valid class extending Person now would be:
class Archie extends Person {
public function hide() {
echo "Hides behind a bush";
}
}
Any class that extends Person must declare a public hide() method.
Interfaces
Finally, you mention interfaces. Interfaces are contracts that implementing classes have to fulfill. They declare a group of public methods without an implementation body.
E.g.:
interface Policeman {
public function arrest(Person $person) : bool;
public function help($what): bool;
}
Now we could have class that extended Person and implemented Policeman:
class Jane extends Person implements Policeman {
public function hide() {
echo "Jane hides in her patrol-car";
}
public function arrest(Person $person): bool{
// implement arrest method
return false;
}
public function shoot($what): bool {
// implements shoot() method
return false;
}
}
Importantly, while it's possible to extend only one class (there is no multiple inheritance in PHP), it is possible to implement multiple interfaces, and the requirements for each of those have to be fulfilled for the class to be valid.
Let say I have a PHP Class:
class MyClass {
public function doSomething() {
// do somthing
}
}
and then I extend that class and override the doSomething method
class MyOtherClass extends MyClass {
public function doSomething() {
// do somthing
}
}
Q: Is it bad practice to change, add and or remove method params? e.g:
class MyOtherClass extends MyClass {
public function doSomething($newParam) {
// do somthing
// do something extra with $newParam
}
}
Thanks
In general, yes it is bad design. It breaks the design's adherence to the OOP principle of polymorphism (or at least weakens it)... which means that consumers of the parent interface will not be able to treat instances of your child class exactly as they would be able to treat instances of the parent.
Best thing to do is make a new semantically named method (semantic in this case meaning that it conveys a similar meaning to the original, with some hint as to what the param is for) which either calls the original, or else in your overridden implementation of the original method, call your new one with a sensible default.
class MyOtherClass extends MyClass {
public function doSomething() {
return $this->doSomethingWithOptions(self::$soSomethingDefaultOptions);
}
public function doSomethingWithOptions($optsParam) {
parent::doSomething();
// ...
}
}
I've seen a few questions with really similar titles but they where irrelevant to my specific problem.
Basically, I want to access the variables from my core class in a class which extends core, but things seem to be quite complicated compared to other examples. I am using a MVC framework. I've simplified the code below to remove anything that was irrelevant.
index.php
// Load the core
include_once('core.php');
$core = new Core($uri, $curpath);
$core->loadController('property');
core.php
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once('controller/'.$name.'.php');
$controller = new $name();
}
}
property.php
class Property extends Core
{
function __construct()
{
print $this->curpath;
}
}
Printing $this->curpath just returns nothing. The variable has been set but it is empty.
If I print $this->curpath inside core.php it prints fine.
How can I access this variable?
You are doing it wrong tm
You should be utilizing an autoloader, instead of including files with each class manually. You should learn about spl_autoload_register() and and namespaces, and how to utilize both of them.
Do not generate output in the __construct() methods. That's an extremely bad practice
The variables are still there. That is not the problem. In PHP, when you extend a class, it does not inherit the constructor.
You do not understand how inheritance works. When you call method on instance of extended class it will not execute parent class's method , before calling extended class's methods. They get overwritten , not stacked.
Object variables should not be exposed. You are breaking the encapsulation. Instead og defining them as public you should use protected.
You should extend classes of they are different type same general thing. The extends in PHP means is-a. Which means that, when you write class Oak extends Tree, you mean that all the oaks are trees. The same rule would mean, that in your understanding all Property instances are just a special case of Core instances. Which they clearly ain't.
In OOP, we have principle. One of which is Liskov substitution principle (shorter explanation). And this is the thing your classes are violating.
The problem, I think, lies here:
If you consider a simple inheritance like this one:
class Dog{
public $color;
public function __construct($color){
$this->color = $color;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
}
}
//Create Dog:
$alfred = new Dog('brown');
//Create TrainedDog
$lassie = new TrainedDog('golden',array('fetch'));
In this example $alfred is a brown dog and $lassie is a golden dog. The two instances are separate from each other, the only thing they have in common is that they both have a property called $color.
If you want a variable that is available in all Dogs for example, you need a class variable:
class Dog{
public $color;
public static $numberOfLegs; //Class variable available in every instance of Dog.
public function __construct($color, $numberOfLegs){
$this->color = $color;
self::$numberOfLegs = $numberOfLegs;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
echo parent::$numberOfLegs;
}
}
This does not make much sense in many cases though, because if you have two instances of the parent class (in you're case Core), they also share the class variable.
Unless you can ensure that Core is instanciated only once, this approach will not work. If it does only exist once, you can just as well use constant variables to store the 2 properties.
If there exist multiple instances/objects of Core, I'd recommend using a composition (as suggested by Alvin Wong).
class Core{
//Just as you programmed it.
}
class Property{
private $core;
public function __construct($core){
$this->core = $core;
echo $core->curPath;
}
}
Try this
include_once('core.php');
$core = new Core('test', 'path');
$core->loadController('property');
class Property extends Core
{
function __construct($date)
{
print $date->curpath;
}
}
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once($name.'.php');
$controller = new $name($this);
}
}
In the project my team is currently working on, we're modifying a commercial PHP application. The app is strewn with code where a parent class checks for and works with a property that doesn't exist in the parent class, like so:
class A
{
function doSomething()
{
if (property_exists($this, 'some_property'))
{
$this->some_property = $_REQUEST['val'];
}
}
}
class B extends A
{
protected $some_property;
function doSomething()
{
parent::doSomething();
}
}
We feel vaguely dirty having to modify this code; is this proper design? What are the ways (other than the obvious) something like this can be avoided?
You might consider abstracting the parent class. So the methods that the children must have are declared in the parent, but not implemented.
Relying upon methods that must exist in a subclass is not dirty, as long as you can declare them as abstract.
However, it is not good practice to rely on and manipulate properties outside of a class. It's best to use abstract setters, like this:
abstract class A
{
abstract protected function setSomeProperty($data);
public function doSomething()
{
$this->setSomeProperty($_REQUEST['val']);
}
}
class B extends A
{
private $some_property;
public function doSomething()
{
parent::doSomething();
}
protected function setSomeProperty($data)
{
$this->some_property = $data;
}
}
More info here: PHP Class Abstraction
However, since you said you're not allowed to modify the parent class, I would suggest making a subclass that acts as an Adapter to what the parent class "expects", and a class that you're able to design "properly".
You can create a virtual method hook in the parent class which can later be overridden by children.
I think it's more neat to create a sub-class, where all members have function doSomething(). In that case you don't create a not-working function in a parent class (with eventual hacks), but still have the general "super-function".
class A
{
}
class C extends A {
protected $some_property;
function doSomething()
{
$this->some_property = $_REQUEST['val'];
}
}
class B extends C
{
protected $some_property;
function doSomething()
{
parent::doSomething();
}
}