I currently have an abstract class which i am extending to other controllers. I have a abstract function within the abstract class which takes the value and places it in the __construct.
abstract class Controller extends BaseController {
abstract public function something();
public function __construct(Request $request) {
if (!is_null($this->something())){
$this->global_constructor_usse = $this->something();
}
}
}
My problem is that, on controllers that don't require this abstract function, I am having to place in the empty function.
class ControllerExample extends Controller {
public function something(){
return 'somethinghere';
}
}
Is there anyway to making the abstract function optional, or have a default value?
class EmptyControllerExample extends Controller {
public function something(){}
}
It is not possible to have a abstract method optional, as it is implied in PHP that all abstract methods must have an implementation.
There are legit use cases for optional abstract methods, yes: event handlers, metadata describers, etc. Unfortunately, you'll need to use regular, non-abstract methods with an empty body, and indicate in PHPDoc that they will do nothing unless extended.
Be wary, though: this can very quickly turn into code smell by diffusing a class responsability with their children. If you're dealing with generic events, you can look into Laravel's own event system, or the Observer pattern instead.
Abstract functions in a parent class, should only be used if its required by your application to implement the following method in all controllers who inherits from it, clearly it is not the case.
In this case i would make a trait. Here you create a trait which can be implemented by the classes who needs it. Notice the use keyword usage, use somethingTrait;
trait SomethingTrait
{
public function something()
{
echo "something called";
}
}
class Controller
{
use SomethingTrait;
public function run()
{
$this->something();
}
}
phpfiddle link
Another aproach could be doing a class inheritance structure, if the controllers you want to implement the methods has something in common. Where you would implement your special method in CrmController, where you still would be able to create shared methods in the abstract controller.
AbstractController
|
CrmController
|
CompanyController
For your question, 'Is there anyway to making the abstract function optional or have a default value?' No, and you are down the wrong path if you are trying to make abstract function optional. Hope my suggestions can help.
Related
So I have a question about the difference between "when we should declare normal function" and "when we should declare abstract function" in base class. Look at my example.
In the abstract class:
abstract class Birds {
abstract public function fly();
}
class Swallow extends Birds {
public function fly() {
// This function override fly function in Birds class
echo "Implement fly function in Swallow class";
}
}
In the normal class:
class Birds {
public function fly() {
echo "Implement fly function in Birds class";
}
}
class Swallow extends Birds {
public function fly() {
// This function override fly function in Birds class
echo "Implement fly function in Swallow class";
}
}
What you can see. The fly function in Swallow class is inherited by Birds class (in all cases). They are a same thing. So I'm embarrassed and I dont know when we should declare abstract function in base class?
Thanks for your help!
Abstract functions are actually only an interface. E.g. there's no difference in your example between abstract class and if it would be an interface (that's because there's only abstract method).
//abstract class
abstract class Birds {
abstract public function fly();
}
//interface
interface Birds {
public function fly();
}
That's because abstract methods have the same purpose that interface's method. When you somewhere else create a function (or method or a class or another interface etc.), and you will require any Birds instance, you will be sure you have that abstract method avaiable, although it was not implemented in Birds.
public function sendBirdToSpace(Birds $bird) { //no matter what Bird subclass
$bird->fly(); //you're sure this method is avaiable
}
Also usually you will have more than one child class. When it comes to that, it's getting more clear about abstract method.
It's actually pretty simple. Should Birds have a default behaviour implementation of flying? That's all. If every bird should can fly, but there's no default method - make it abstract.
Taken from PHP OOP Class Abstraction:
When inheriting from an abstract class, all methods marked abstract in
the parent's class declaration must be defined by the child;
additionally, these methods must be defined with the same (or a less
restricted) visibility. For example, if the abstract method is defined
as protected, the function implementation must be defined as either
protected or public, but not private.
This is essentially saying that your Swallow class has to inherit (have) the fly() method in it if it extends the Bird class based off of its abstract definition.
The general rule of thumb when harnessing abstract methods is when you want normality among classes.
Take the following for example:
Class Car {
abstract public function make();
abstract public function model();
}
This is our "base" class. Anything that extends from this has to specify the make() & model() methods.
Class Tesla extends Car {
public function make() {}
public function mmodel() {}
}
As you see above, our Tesla class has the required methods within. If you do not include these methods, you'll have PHP errors thrown.
Note
If you're exploring this option of "container" like development, then I'd suggest that you have a good look at PHP OOP Object Interfaces too, well worth it!
I'm facing the following issue in PHPStorm 9:
Say I have an interface FieldInterface that has some methods:
namespace Acme;
interface FieldInterface {
public function methodA();
public function methodB();
}
then I have an abstract class that implements base functionality of the interface. That abstract class has the user to implement certain methods, let's say it's methodB in our example:
namespace Acme;
abstract class AbstractField implements FieldInterface {
public function methodA() {
// implement methodA
}
public abstract function methodB(); // have the user implement it
}
And finally I have some ready-to-use class StringField:
namespace Acme;
class StringField extends AbstractField {
public function methodB() {
// implement methodB
}
}
At this point everything's going well. But if I add new method in the FieldInterface, PHPStorm does not say that anything is wrong with AbstractField while it's obvious that I should add public abstract function newMethod(); in there. However, it spots the error in StringField class instead.
It could be understood from the point that abstract classes are made for the purpose of extention, but usually you extend the abstract class rather than implement underlying interface. The whole meaning of making abstract class is to save user's time for implementing the interface. So why PHPStorm forces me to implement interface in concrete class rather than forcing me to implement it in abstract class that is explicitly implements the interface.
So I wonder if it is a bug in PHPStorm, or maybe it's done on purpose. Either way, is there any workaround?
That's how it should be, showing an error in the abstract class would be wrong.
In fact, public abstract function methodB(); is redundant because the abstract class already "inherits" this abstract method from the interface as it does not implement it.
The only workaround is to make AbstractField not abstract.
This is a follow-up to my previous question about resolving the diamond issue in php.
As I state in that question, I resolve my problem by using traits and passing the instance of the class to the method of the trait. Such as:
trait SecurityTrait
{
public function beforeExecuteRouteTrait($controller, Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
return $this->beforeExecuteRouteTrait($this, $dispatcher);
}
}
However, I am still uncomfortable with this as I don't think this is how traits are really supposed to be used. In my reading I haven't found any way in which to access class members in traits (make $this inside a trait refer to the class using it). Is this possible? Or is there another way to implement a similar behaviour?
After reading some of the answers...
Previously I thought I had received errors when using $this->... inside the trait and this led me to believe the trait could not access anything to do with the underlying class. After reading the answers I tried altering my code to use $this->... inside a trait again and it works - which means a typo several weeks ago has given me far too much headache...
The example given previously now looks like this
trait SecurityTrait
{
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
}
Much cleaner and more easily understandable but provides the same functionality.
If you use a trait inside a class then that trait has full access to all class's members and vice versa - you can call private trait methods from the class itself.
Think of traits as code that literally gets copy/pasted into the class body.
For example:
trait Helper
{
public function getName()
{
return $this->name;
}
private function getClassName()
{
return get_class($this);
}
}
class Example
{
use Helper;
private $name = 'example';
public function callPrivateMethod()
{
// call a private method on a trait
return $this->getClassName();
}
}
$e = new Example();
print $e->getName(); // results in "example"
print $e->callPrivateMethod(); // results in "Example"
In my view referencing classes in traits is not the best way to use them but there's nothing stopping anyone from doing it.
No, that's exactly what Traits are for. Your class already extends a class so you can't inherit the methods and variables of any other classes.
Think of a Trait like copy/paste for code execution. When a class includes a Trait, it's just as if you had written all that code into the class itself.
I'm stuck into a problem with traits I can't solve on my own.
I have classes extending an abstract class (in my case these are several controller classes and an abstract class Controller, the used framework won't be important here, since this is a general PHP question…) that uses traits. I'd like to override a method defined in one of the traits. This only works as long as I define the method in my sub-classes but not in my abstract class.
So, this one works perfectly:
class MyController extends Controller
{
use AnyTrait;
public function anyMethodFromAnyTrait()
{
// override AnyTrait::anyMethodFromAnyTrait()
}
}
I also know how to call the anyMethodFromAnyTrait method from AnyTrait by using as.
class MyController extends Controller
{
use AnyTrait { AnyTrait::anyMethodFromAnyTrait as method }
public function anyMethodFromAnyTrait()
{
// invoke AnyTrait::anyMethodFromAnyTrait()
$this->method();
}
}
Both work like a charm.
But my problem is a bit different.
When using the trait and defining the method in my abstract class I am not able to override the trait's method.
Assume the following controller class:
class MyController extends Controller
{
public function anyAction()
{
// let's see what happens…
$this->anyMethodFromAnyTrait();
}
}
…and the abstract one that's extended by MyController:
abstract class Controller
{
use AnyTrait
public function anyMethodFromAnyTrait()
{
// do something different than AnyTrait
}
}
…And this is what's not working at all. Whenever I call $this->anyMethodFromAnyTrait() within MyController the trait's method as implememented in AnyTrait will be invoked. The same named method in my abstract Controller will be ignored.
Therefore I only can override a trait's method in a concrete sub-class but not in an abstract class that is extended by that sub-class.
So the method definitions in traits get a higher priority by PHP than the same method definitions in abstract classes.
Do you know any workaround for that behaviour?
One workaround would be to use the traits ONLY in the subclasses.
PHP always prefers the trait methods over the "local" ones.
The reason why it works in subclasses is, that the trait method of the superclass is extended, not the trait usage itself.
i would like to know if it is possible to have a function in PHP which returns an interface or a class which contains an interface?
i tried something like this, but it fails
<?php
//class for list of controllers for ACL
class Gestionale_Action_Helper_Crud extends Zend_Controller_Action_Helper_Abstract {
interface crud_controller
{
public function indexAction();
public function modificaAction();
public function cancellaAction();
public function creaAction();
}
public function getCrudInterface(){
return $this->crud_controller;
}
}
what i wanted to do, in zend framework, create an interface that crud controllers must implement, or even better if i could create an abstract controller and have them implement that
thank you
I'd suggest that you use Zend_Rest_Controller instead of creating your own interface.
Zend_Rest_Controller is an abstract class that defines five basic methods you need in a CRUD-controller: index, get, post, put, and delete.
Combined with Zend_Rest_Route it lets you create nice and clean RESTful application.
You can get more reading on Zend_Rest_Controller at http://weierophinney.net/matthew/archives/228-Building-RESTful-Services-with-Zend-Framework.html and http://techchorus.net/create-restful-applications-using-zend-framework
Just place the interface outside of any class (preferably in a different file) and let it be implemented by all your crud-controllers.
<?php
class GrudController implements CrudInterface
{
// ...
}
i'm not sure i get what it is you want to do, but i'm fairly certain you're asking the wrong question. if you simply want to make sure an object implements a certain interface, this is quite easy to do. lets say for example you have some helper method in a class which deals with a crud controller, you just specify the type in the argument list:
class crud_helper {
public function help(crud_controller $cc) {
$cc->indexAction();
}
}
now you can pass any object that is an instance of a class that implements crud_controller to the method help. but no other object.