Is it OK (good practice OOP wise) to make a class implement a certain interface so that a trait being used in that class can access the classes functions.
I found a SO question a few days ago with an answer explaining that traits shouldn't use methods/things from the class it's being used in. What If I made a class implement an interface so it had to have those functions that the trait uses from the class? Would that be OK. I'm taking an OOP class in university next year, so I only learned what OOP I did from the internet, in case this is a bad question. :p
So here's the idea to clarify (in PHP)
trait MyTrait {
public function foo() {
return $this->bar(); // bar is in the class the trait is to be used in
}
}
class MyClass implements MyTraitCompatible {
public function bar() {
return "BAR!";
}
}
interface MyTraitCompatible {
public function bar();
}
Also, is there anyway to enforce that a class needs to implement MyTraitCompatible to use MyTrait?
Edit: (My actual goal is to have one function used in two classes that both extend another class (Eloquent) and would be completely identical but the function would not be used in all classes extending Eloquent - this is one way I thought of doing it.)
One option is that your trait could check that the class using it implements the interface you expect. Here's an example in the constructor method:
trait MyTrait {
public function __construct() {
if (!in_array('MyTraitCompatible', class_implements($this, false))) {
throw new Exception('To use this trait you must implement MyTraitCompatible!');
}
}
public function foo() {
return $this->bar(); // bar is in the class the trait is to be used in
}
}
A valid class would be:
class MyClass implements MyTraitCompatible {
use MyTrait;
public function bar() {
return "BAR!";
}
}
An invalid class would be:
class InvalidClass {
use MyTrait;
public function baz() {
return "I don't think so buddy.";
}
}
Obviously if the class using this trait has a constructor already then this would conflict. There isn't a pretty way to avoid this since the class using the trait will have precedence over the trait and would just override it. One option is that you could define a check method in the trait and call it from the methods in the trait to check compatibility, but it's not ideal:
trait MyTrait {
protected function compatible() {
if (!in_array('MyTraitCompatible', class_implements($this, false))) {
throw new Exception('To use this trait you must implement MyTraitCompatible!');
}
var_dump('Passed the test!');
}
public function foo() {
$this->compatible();
return $this->bar(); // bar is in the class the trait is to be used in
}
}
You could also replace that compatible() method with the __call() magic method - but again, you might run into conflicts if you have one defined elsewhere.
Related
I've already read Why does PHP 5.2+ disallow abstract static class methods? and How to force an implementation of a protected static function - the second is very similar to my case - but I am still without answer. Basically, I want to assure, that every child of my abstract class has implementation of protected static method, without implementing it as this has no meaning and because of lack of key informations there. Also, it must be static (because caller method is static and it has no context) and protected (so I cannot use interface, and I do not want anyone to call it directly), and it will be called by late static binding. Any ideas?
Dummy code below to illuminate my case:
abstract class BaseClass {
public static function foo() {
// some common stuff
static::bar();
// rest of common stuff
}
public function whoooaaa($condition) {
if ($condition) {
AClass::foo();
} else {
BClass::foo();
}
}
}
class AClass extends BaseClass {
protected static function bar() {
// do something
}
}
class BClass extends BaseClass {
protected static function bar() {
// do something else
}
}
// end somewhere else in my code, two constructions, both used:
AClass::foo();
// ....
$baseClassInheritedInstance->whoooaaa($variableCondition);
My only solution, ugly one, is to implement dummy protected static method in base class and throw a generic exception, so that it must be implemented by inheritance.
You can add a static factory that will fill context for casual objects.
class Factory() {
public static getObject($condition) {
$object = $condition ? new A() : new B();
// you can fill context here and/or use singleton/cache
return $object;
}
}
abstract class Base {
abstract function concreteMethod();
}
class A extends Base {...}
class B extends Base {...}
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();
// ...
}
}
What is implementing a function? normally, what I know is implementing an interface which has
function foo();
and implementing like
function foo($bar)
in another class
but what happens when I implement the function in the interface? do I have to reimplement them in the subclasses? or can I use them in subclasses directly, assuming they are implemented in the subclasses.
interface ibarbar{
function foo($bar)
{
return $bar.$bar;}
}
class barbar implements ibarbar
{
function baz()
{
$this->barbar(); //used without implementing in subclass. expected results unknown.
}
}
PHP documentation says
// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
}
so all methods in an interface are abstract methods. but I couldn't find how to extend a function. or implement a function
You can't implement a function in an interface. You can only specify its signature.
If you want to specify signatures for some methods but provide implementation for others, use an abstract class:
abstract class A {
abstract public function B($c);
public function C($d) {
// do something
}
}
class B extends A {
public function B($c) { // need to implement B, as it is abstract
$this->C($c); // but can directly use C, as it is not
}
}
An interface has no implementation, by definition.
You're talking inheritance, here, if you have a function having an implementation that you override / Shadow in another class.
In PHP, can I specify an interface to have fields, or are PHP interfaces limited to functions?
<?php
interface IFoo
{
public $field;
public function DoSomething();
public function DoSomethingElse();
}
?>
If not, I realize I can expose a getter as a function in the interface:
public GetField();
You cannot specify members. You have to indicate their presence through getters and setters, just like you did. However, you can specify constants:
interface IFoo
{
const foo = 'bar';
public function DoSomething();
}
See http://www.php.net/manual/en/language.oop5.interfaces.php
Late answer, but to get the functionality wanted here, you might want to consider an abstract class containing your fields. The abstract class would look like this:
abstract class Foo
{
public $member;
}
While you could still have the interface:
interface IFoo
{
public function someFunction();
}
Then you have your child class like this:
class bar extends Foo implements IFoo
{
public function __construct($memberValue = "")
{
// Set the value of the member from the abstract class
$this->member = $memberValue;
}
public function someFunction()
{
// Echo the member from the abstract class
echo $this->member;
}
}
There's an alternative solution for those still curious and interested. :)
Use getter setter. But this might be tedious to implement many getters and setters in many classes, and it clutter class code. And you repeat yourself!
As of PHP 5.4 you can use traits to provide fields and methods to classes, ie:
interface IFoo
{
public function DoSomething();
public function DoSomethingElse();
public function setField($value);
public function getField();
}
trait WithField
{
private $_field;
public function setField($value)
{
$this->_field = $value;
}
public function getField()
{
return $this->field;
}
}
class Bar implements IFoo
{
use WithField;
public function DoSomething()
{
echo $this->getField();
}
public function DoSomethingElse()
{
echo $this->setField('blah');
}
}
This is specially usefull if you have to inherit from some base class and need to implement some interface.
class CooCoo extends Bird implements IFoo
{
use WithField;
public function DoSomething()
{
echo $this->getField();
}
public function DoSomethingElse()
{
echo $this->setField('blah');
}
}
Interfaces are only designed to support methods.
This is because interfaces exist to provide a public API that can then be accessed by other objects.
Publicly accessible properties would actually violate encapsulation of data within the class that implements the interface.
You cannot specify properties in an interface : only methods are allowed (and make sense, as the goal of an interface is to specify an API)
In PHP, trying to define properties in an interface should raise a Fatal Error : this portion of code :
interface A {
public $test;
}
Will give you :
Fatal error: Interfaces may not include member variables in...