OO: Inheritance vs Service [closed] - php

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Class A
{
public function __construct(Foo $foo, Bar $bar, MyCustomType1 $mct)
{
//...
}
//...
public function getFooBarFunction()
{
$this->foo->aMethod();
$this->bar->anotherMethod();
//some other execution here
}
}
Class B
{
public function __construct(Foo $foo, Bar $bar, MyCustomType2 $mct)
{
//...
}
//...
public function getFooBarFunction()
{
$this->foo->aMethod();
$this->bar->anotherMethod();
//some other execution here (same of Class A)
}
}
Class C
{
public function __construct(Foo $foo, Bar $bar, MyCustomType3 $mct)
{
//...
}
//...
public function getFooBarFunction()
{
$this->foo->aMethod();
$this->bar->anotherMethod();
//some other execution here (same of Class B and Class A)
}
}
As you can see this code doesn't respect the DRY principles. I can easily collapse getFooBarFunction() into another class and use that method.
A) Create a SuperClass and migrate getFooBarFunction() into it. I need to replicate __construct() also ($this-> references).
Pros
- quite easy to do
- I can create an interface for MyCustomType(s) and use that into construct in substituion of concrete class(es)
Cons
- what if child class need to add a parameter into construct phase?
- what if I can't group MyCustomType(s) under same interface?
B) Create a SuperClass and use setters to "inject" Foo and Bar objects
Pros
- quite easy too
- I don't need to share constructor
Cons
- what if I forgot to inject parameters? Have I to add additional explicit checks into SuperClass and raise exceptions?
C) Create a SuperClass and let getFooBarFunction() accept Foo and Bar objects
Pros
- quite easy too
- I don't need to share constructor
Cons
- Is really necessary, in that case, inheritance?
D) Create an indipendent class (service?) and let A,B,C instantiate it and use it directly
What's best approach (or the "best practice") and why? There are any others?
UPDATE
Class A, Class B and Class C are some objects that doesn't share any information each others (they represent a Room, a Service, a Supplement). Only common feature is that every class has a relationship with i18n table (each one with his own table). So my getFooBarFunction() is only a function used to retrieve static types (stored somewhere, it's not important) that indicates the type of i18n text (title, description, short name, and so on)
UPDATE2 Real code
private function getTextTypeNameEntity()
{
$text_type_repository = $this->getTextTypeRepository();
$text_type_name_id = $this->container->getParameter('foo_project.text_type.name');
$text_type_name = $text_type_repository->findOneById($text_type_name_id);
return $text_type_name;
}
this function is getFooBarFunction()

Answer for update 2
You say this function only fetches text from an repository by an unique id. Without knowing the complete class this sounds like a code smell. A class should only do one thing and do it well. When you implement features, which are not strictly related, you extend the class over is boundaries. I would change the getFooBarFunction to only provide the text id:
public function getTextId() {
return 'some-awesome-unique-text-id';
}
Original post
When looking at the code you provided I can only see one difference, the MyCustomType. I would type hint a shared interface which implements the signature for each method that can be called (interface basics). This can also be applied to the Foo and Bar classes. By using interfaces you can more easily swap actual class implementations.
You said: "What if I cannot group my custom type under the same interface?". This is tricky and one of the hard things to do with interfaces. Think of interfaces as a contract. If you change the method signatures of a class, but tries to use it in place of another you are guaranteed to run into errors. This will also make your code harder to maintain/read as you will attempt to handle edge cases all over the place. Try to stick with the interface.
You said: "what if I forgot to inject parameters?". First off this should be considered a bug/error and you as developer is responsible, sorry :D
You then later said, "what if I need to pass another parameter during construction?". To me that sounds like a different class all together and should be treated as such. Then if you need another parameter anyway, you can just extend this class and overwrite only the constructor. Something like the following.
abstract class AbstractImplementation {
public function __construct(FooInterface $foo, BarInterface $bar, CustomInterface $custom) {
// Initialize properties.
}
/*
* This could also be declared abstract if each implementation
* is different.
*/
public function getFooBarFunction() {
// Perform basic actions
}
}
class ActualImplementation extends AbstractExample {
public function getFooBarFunction() {
// Perform specific actions
}
}
Then if you need another parameter you can do. This should be considered an edge-case.
class ExtendedImplementation extends ActualImplementation {
public function __construct(Extra $extra, FooInterface $foo, BarInterface $bar, CustomInterface $custom) {
parent::__construct($foo, $bar, $custom);
$this->extra = $extra;
}
}
Hope my thoughts can help you, happy coding!

I would opt for D + interfacing your classes. If getFooBarFunction() has nothing to do with the inner workings of A,B or C and the implementation is always the same in all classes then it shouldn't be a member of those classes. If the code calling A,B and C needs to know, that the method is there I would extract getFooBarFunction() in an interface and implement that in A,B and C. This way, the code outside can be sure the method is always there and is implemented in a working way.

Related

unit tests and object-inheritance

I have a question concerning "unit tests" and object-inheritance. For example:
I have a class A which extends class B. Let's assume the only difference of the two classes is the add method . In class B this add method is slightly extended. Now I want to write a unit test for the add function of class B but because of the parent::add call I have a dependency to the parent class A. In this case I can't mock the add method of the parent class so the resulting test will be a integration test but if I want it to be a unit test? I don't want the the test for method add in class B fails because of the parent method in class A. In this case only the unit-test of the parent method should fail.
class B exends A
{
public function add($item)
{
parent::add($item);
//do some additional stuff
}
....
}
class A
{
protected $items = [];
public function add($item)
{
$this->items[] = $item;
}
....
}
Surely I could use object-aggregation and pass my parent object to the child contructor and therefore I would be able to mock the parent method add, but is this the best approach? I would rarely use object-inheritance anymore.
class B
{
protected $a;
public function __contruct(A $a)
{
$this->a = $a;
}
public function add($item)
{
$this->a->add($item);
//do some additional stuff
}
....
}
class A
{
protected $items = [];
public function add($item)
{
$this->items[] = $item;
}
....
}
I would be very grateful for your opinions. Thanks!
Ask yourself, what kind of inheritance do you want to achieve? If B is a kind of A, then you're wanting interface inheritance. If B shares a lot of code with A, then you're wanting implementation inheritance. Sometimes you want both.
Interface inheritance classifies semantic meaning into a strict hierarchy, with that meaning organized from generalized to specialized. Think taxonomy. The interface (method signatures) represent the behaviors: both the set of messages to which the class responds, as well as the set of messages that the class sends. When inheriting from a class, you implicitly accept responsibility for all messages the superclass sends on your behalf, not just the messages that it can receive. For this reason, the coupling between super- and sub-class is tight and each must strictly substitute for the other (see Liskov Substitution Principle).
Implementation inheritance encapsulates the mechanics of data representation and behavior (properties and methods) into a convenient package for reuse and enhancement by sub-classes. By definition, a sub-class inherits the interface of the parent even if it only wants the implementation.
That last part is crucial. Read it again: Sub-classes inherit the interface even if they only want the implementation.
Does B strictly require the interface of A? Can B substitute for A, in all cases matching co-variance and contra-varience?
If the answer is yes, then you have true sub-typing. Congratulations. Now you must test the same behaviors twice, because in B you are responsible for maintaining the behaviors of A: for every thing A can do, B must be able to do.
If the answer is no, then you merely need to share the implementation, test that the implementation works, then test that B and A separately dispatch into the implementation.
In practical terms, I avoid extends. When I want implementation inheritance, I use trait to define static behaviors † in one place, then use to incorporate it where needed. When I want interface inheritance, I define many narrow interface then combine with implements in all the concrete types, possibly using trait to leverage behavior.
For your example, I'd do this:
trait Container {
public function add($item) { $this->items[] = $item; }
public function getItems() { return $this->items; }
private $items = [];
}
interface Containable { public function add($item); }
class A implements Containable { use Container; }
class B implements Containable {
use Container { Container::add as c_add; }
public function add($item) {
$this->c_add($item);
$this->mutate($item);
}
public function mutate($item) { /* custom stuff */ }
}
Container::add and B::mutate would have unit tests, while B::add would have an integration test.
In summary, favor composition over inheritance because extends is evil. Read the ThoughtWorks primer Composition vs. Inheritance: How To Choose to gain a deeper understanding of the design trade-offs.
† "static behaviors", you ask? Yes. Low-coupling is a goal and this goes for traits. As much as possible, a trait should reference only variables it defines. The safest way to enforce that is with static methods that take all their input as formal arguments. The easiest way is to define member variables in the trait. (But, please, avoid having traits use member variables that are not clearly defined in the trait -- otherwise, that's blind coupling!) The problem, I find, with trait member variables is that when mixing in multiple traits you increase the chance of collision. This is, admittedly, small, but it is a practical consider for library authors.

OOP (PHP) - Force overridden method to call according parent-method

I have a general problem with this use case: I have a class A. This class has a non-abstract method doStuffCallback() which could be overridden but it's not necessary for every subclass. But: I want to ensure that if the method is overriden the subclass-method must call the parents method.
Example:
abstract class A {
private function doStuff() {
$this->doStuffCallback();
}
protected function doStuffCallback() {
// IMPORTANT CODE HERE
}
}
class B extends A {
protected function doStuffCallback() {
parent::doStuffCallback(); // I want to enforce this because the parents method code is important
// ALSO IMPORTANT CODE
}
}
Because the overridden method does the same thing it would be very ugly to define two methods for the same responsibility and a private helper-method which calls both. Like this:
abstract class A {
private function doStuff() {
$this->callDoStuffCallback();
}
private function callDoStuffCallback() {
$this->internalDoStuffCallback();
$this->doStuffCallback();
// This is VERY ugly
}
private function internalDoStuffCallback() {
// IMPORTANT CODE HERE
}
protected function doStuffCallback() {}
}
class B extends A {
protected function doStuffCallback() {
// IMPORTANT CODE
}
}
This is really ugly and laborious. So my question: Is there a way in PHP to force overriden methods to call the parents method?
No. There is no such language feature in PHP; this restriction is not possible in most subtype-'OO' languages.
Instead programs must rely on explicit documentation contracts; and hopefully, unit testing to ensure conformance.
Guards may also be employed such that, at some point by and by when a method on the parent class is used, it could throw an exception if the 'current state' is not valid (eg. such and such a method has not been called yet). This may also be made more explicit by making the subclass required to call (as defined in the documentation contract) some special method, instead of simply the overriden super method. However, such is outside of any type system.
While the self:: scope could be used (eg. call non-overriden method which calls overriden method), this would involve further magic (eg. some stack state) to avoid infinite recursion loops; and it would be as easy to accidentally omit usage.
My recommendation is to call a (private) method that calls this 'maybe overriden' method in relationship to whatever logic applies, as shown in the example (although hopefully with more task specific tames). Then the (protected) overriden method is not expected or required to handle any of the special logic itself; nor is it meant to be called directly outside of the context established by the parent class - it is just what it currently claims to be, a special callback.
I tend to disagree with "This is VERY ugly". It is the standard way of handling this use case and a variant of the Template Method Pattern.
Now I am just guessing because you did not provide a real example but if you say that the two methods "do the same thing", there might be something wrong with your design. If they do the same thing, why is calling the parent implementation necessary if the subclass does the same thing in a different way? To me it sounds like the method actually does more than one thing and you might be able to break it down into several parts that can be overridden individually (or not, then make them private or final).
I know this is an old topic but I was asking myself the same question and what I did is :
abstract class A {
private function doStuff() {
$this->doStuffCallback();
}
final protected function doStuffCallback() {
// IMPORTANT CODE HERE
$this->callNewFunction();
}
abstract protected function callNewFunction();
}
class B extends A {
protected function callNewFunction() {
// ALSO IMPORTANT CODE
}
}
So basically I would mark as "final" the function you wish to force the code for every child and then call a new "Abstract" function to force the childs to implement it. If you do not wish to force the new "Abstract" function, simply don't make it abstract.
Edit : This is basically #Fabian Schmengler's answer but more concrete with your example.
No, you can access, you can use method for parent, like this
<?php
class A {
function s1($p1) {
echo 's1: '.$p1;
}
}
class B extends A {
public function callParent($method, $p1) {
parent::$method($p1);
}
}
$b = new B();
$b->callParent('s1', 'param1');
or replace extending on magic methods __call and etc. https://github.com/StagnantIce/php_extend_magic/blob/master/AExtendClass.php

How to name my classes? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I have a base user class which is responsible for manipulating the basic user information: name, age, location, etc. I want to extend my system with the groups functionality and later with projects and meetings. For example:
class User
{
public function getName() {
...
}
public function getAge() {
...
}
}
And then extend it with groups functionality:
class GroupableUser extends User
{
public function join($groupId) {
...
}
public function leave($groupId) {
}
public function requestGroupInvitation($groupId) {
...
}
public function acceptGroupInvitation($groupId) {
...
}
}
The name GroupableUser seems weird to me, however it does't make sense to add join and leave methods to Group class, because its user that joins and leaves a group, not the other way around.
And later I would have classes like UserThatCanHaveProjects and UserThatCanParticipateInMeetings.
How to name these classes?
And how do you typically deal with these situations?
You can't seem to be able to find a way to name the classes because the hierarchy is not very natural. In reality a user may participate in more than one group and each group may have more than one user. But a user may exist without a group, while there can't be a group without a user. I would say this means users should be a member of a group and addUser and removeUser should be placed in Group. Why? Because a user may not even "know" that he may join or leave a group and be perfectly happy, while there can not be a group that does not "know" that a user may join it.
The capability to participate in groups/meetings and have projects is something that a user might be able to do, but it's not something that defines what a user is. This is a pretty clear sign that modelling these options with additional classes is not a good design choice.
Static approach #1: interfaces
In a statically typed language a simplistic implementation would look something like
interface IGrouppableUser {
public function join(...);
}
class GroupableUser implements IGrouppableUser {
public function join(...) { /* implementation */ }
}
And the consumers of grouppable users would accept IGrouppableUser, allowing you to craft as many classes as necessary. You can also do this in PHP, but as mentioned earlier it's probably not a good design no matter what the language.
As a footnote, I should add that with the addition of traits to the language starting from PHP 5.4 the above scenario can be implemented a bit more conveniently (classes can use a trait instead of implementing an interface, which means you don't need to copy/paste the implementation of join all around the code base). But conceptually it's the exact same approach.
The main disadvantage of this approach is that it does not scale. It might be OK if you only need two or three types of users.
Static approach #2: "not supported" exceptions
If most of the users are grouppable and can have projects then it doesn't make much sense to create a hellish hierarchy of classes; you can just add the necessary members to class User, making it a fat interface:
class GroupableUser implements IGrouppableUser {
private $isGrouppable = true; // default, can be changed at runtime
public function join(...) {
if (!$this->isGrouppable) throw new Exception("User is not grouppable!");
// real implementation
}
}
The main disadvantage of this approach is that it makes the class User appear to unconditionally support a wide range of operations when in fact it does not and as a result can make coding tedious and error-prone (lots of try/catch). It might be OK if the vast majority of users support the vast majority of operations.
Dynamic approach #1: behaviors
It would be much better to conditionally allow User instances to participate in these operations. This means that you need to be able to dynamically attach "behaviors" to User objects, which is fortunately quite easy to do in a dynamically typed language.
I suggest looking up a "behaviors" implementation from an established open-source project, but here's a quick and dirty example:
Behavior base class and sample implementation
abstract class Behavior {
public function provides($name) {
return method_exists($this, $name);
}
public function invoke($target, $name, $arguments) {
array_unshift($arguments, $target);
return call_user_func_array(array($this, $name), $arguments);
}
}
class GrouppableBehavior extends Behavior {
public function join(User $user, $groupName) {
echo "The user has joined group $groupName.";
}
}
Composable (can use behaviors) base class and User implementation
class Composable {
private $behaviors = array();
public function __call($name, $arguments) {
foreach ($this->behaviors as $behavior) {
if ($behavior->provides($name)) {
return $behavior->invoke($this, $name, $arguments);
}
}
throw new Exception("No method $name and no behavior that implements it");
}
public function attach($behavior) {
$this->behaviors[] = $behavior;
}
}
class User extends Composable {}
Test driver
$user1 = new User;
$user2 = new User;
$user1->attach(new GrouppableBehavior);
$user1->join('Test Group'); // works
$user2->join('Test Group'); // throws
See it in action.
The main disadvantages of this approach are that it consumes more runtime resources and that behaviors can only access public members of the classes they are attaching to. In some cases you may find yourself forced to expose an implementation detail that should be private to enable a behavior to work.
Dynamic approach #2: decorators
A variation on behaviors is the decorator pattern:
interface IUser {}
interface IGrouppableUser extends IUser {
public function join(...);
}
class User implements IUser {}
class UserGroupingDecorator implements IGrouppableUser {
private $realUser;
public function __construct(IUser $realUser) {
$this->realUser = $realUser;
}
public function join(...) { /* implementation */ }
/* now you need to implement all IUser methods
and forward the calls to $this->realUser */
/* if IUser exposes bare properties we have a problem! */
}
Using this pattern you can create a UserGroupingDecorator that wraps an IUser at will and pass the decorator to anything that accepts either an IUser or an IGrouppableUser.
The main disadvantage of this approach is that it also does not provide access to the non-public members of User. In addition it rules out exposing bare properties from IUser as there is no way to "forward" bare property accesses from UserGroupingDecorator to $realUser if the properties are also defined on the former -- and you cannot implement IGrouppableUser unless they are indeed defined. This state of affairs can be sidestepped by exposing properties as distinct getter/setter methods, but that means still more code to write.
Thinking in terms of a database-driven web app, I might do this with 5 classes:
1) User
2) Group
3) GroupAssignment
4) GroupInvitation
5) GroupInvitationRequest
Class 3 just maps one User to one Group. Classes 4 and 5 are even more obvious. This setup pretty much matches what you would have in a database anyway. This allows for a good amount of flexibility, as a User could be a member of many groups (or one, or none).
EDIT: Added additional classes based on new information in question.
Groupable would be a good name for interface, Interface should describe an aspect of class, that might be required by instance of some different class. Interfaces are contract between classes.
Just don't stick the "I" in front of it, unless you use hungarian notation for everything. Simply use nouns for class names and adjectives for interfaces.
As for the name of class, I would go with:
class Participant extends User implements Groupable
{
// methods that will be expected by from instance of this class
// by any class that requires an object to have Groupable interfrace
}

PHP Multiple Inheritance with Interfaces

I'm trying to understand how using interfaces gives me multiple inheritance as I've been googling.
class A
{
function do1(){}
function do2(){}
function do3(){}
}
class B extends A
{
function do4(){}
function do5(){}
function do6(){}
}
class C extends B
{
}
In the above example, class C has all the methods from class A and B. However, class B also has all the methods of class A, which is not necessary desired.
My searches have come up to use interfaces to solve this issue by moving methods to a class and creating interfaces, as below.
interface A
{
function do1();
function do2();
function do3();
}
interface B
{
function do4();
function do5();
function do6();
}
class C implements A, B
{
function do1(){}
function do2(){}
function do3(){}
function do4(){}
function do5(){}
function do6(){}
}
I don't really see how this solves the issue because all the code is in the new class. If I just wanted to use class A as originally, I would have to create a new class that implement interface A and copy the same code to the new class.
Is there something I'm missing?
PHP doesn't have multiple inheritance. If you have PHP 5.4, though, you can use traits to at least avoid every class having to copy code.
interface A {
public function do1();
public function do2();
public function do3();
}
trait Alike {
public function do1() { }
public function do2() { }
public function do3() { }
}
interface B {
public function do4();
public function do5();
public function do6();
}
trait Blike {
public function do4() { }
public function do5() { }
public function do6() { }
}
class C implements A, B {
use Alike, Blike;
}
class D implements A {
use Alike;
// You can even "override" methods defined in a trait
public function do2() { }
}
Note, though, you have to both implement the interface and use the trait (or, of course, provide your own implementation). And C and D are not related at all, except in both implementing the A interface. Traits are basically just interpreter-level copy and paste, and do not affect inheritance.
The first thing to understand about interfaces is that they are NOT used for inheritance. That is a very important thing to understand. If you're trying to make several classes share the same concrete code, that is not what an interface is for.
The second thing to understand is the difference between client code, and service code.
Client code is essentially the "last step" in a sequence of requests for data. A controller or a view in MVC can be considered client code. The model, meanwhile can be considered service code.
Interfaces are intended for client code to enforce consistency in the types of data it gets from services. Or another way to think about it - interfaces are a way for services to make sure they will be compatible with a request from client code. That is ALL they do. They quite literally provide an interface by which data is accessed, not an implementation that multiple classes can share.
So to give you a concrete example:
Client Code - a ProfileViewController class for a user's forum profile
class ProfileViewController
{
public function showProfile(User $user)
{
$user->getProfile();
}
}
Service Code - a User model that retrieves data and passes it on to the client code that is requesting it
class User
{
public function getProfile()
{
$profile = Do some SQL query here or something
return $profile;
}
}
Now suppose later on you decide to break up Users into Members, Administrators, Referees, Moderators, Writers, Editors etc, and that each has their own unique type of profile. (e.g. its own custom query, or data, or what have you)
There are now two problems present here:
You need to guarantee that whatever you pass in there will contain a getProfile() method.
showProfile() will fail if you pass in anything other than a User object.
1 is easy to solve through abstract classes and methods (or through Interfaces). 2 at first sounds easy as well, because you can just make Moderators, Admins, and Members all subclasses of a User base class.
But then what happens when down the road, in addition to USER profiles, you want to have generic profiles for things. Perhaps you want to show profiles of sports players, or even profiles of celebrities. They're not users, but they still have profiles/details pages.
Because they're not users, it may not make any sense to consider them subclasses of User.
So now you're a bit stuck. showProfile() needs to be able to accept more than just a User object. In fact, you don't know what type of object you will ultimately want to pass in there. But at the same time, since you always want to be able to grab $user->getProfile(), anything you pass in there must be generic enough to be passed in, AND implement a concrete getProfile() method.
Solution? Interfaces!!!!!
First some service code
// First define an interface for ANY service object that will have a profile
interface IHasProfile
{
public function getProfile();
}
// Next, define the class for an object that should have a profile. I'll do a bunch for the sake of an example...
class User implements IHasProfile
{
public function getProfile()
{
$profile = Your unique user profile query here
return $profile;
}
}
class Celebrity implements IHasProfile
{
public function getProfile()
{
$profile = Your unique celebrity profile query here
return $profile;
}
}
class Car implements IHasProfile
{
public function getProfile()
{
$profile = Your unique vehicle profile query goes here
return $profile;
}
}
Next, the client code that will use it
class ProfileViewController
{
public function showProfile(IHasProfile $obj)
{
$obj->getProfile();
}
}
And there you have it. showProfile() has now been abstracted enough that it doesn't care what object it gets, it only cares that the object has a public getProfile() method. So now you can create new types of objects to your heart's content, and if they are intended to have profiles, you can just give them "implements IHasProfile" and they will automatically just work with showProfile().
Kind of a contrived example, but it should illustrate at least the concept of interfaces.
Of course, you could just be "lazy" and not typecast the object at all, and thus allowing ANY object to be passed in. But that's a separate topic entirely ;)
Multiple inheritance is possible only for Interfaces!
such as my output for it:
php > interface A{};
php > interface B{};
php > interface C extends A,B{};
php > class D implements C{};
php > $d = new D();
php > echo ($d instanceof A);
1
I created A and B interfaces and C interface extends them.
After we have D class which implements C interface
Finally, I ask if $d object is instanceof A interface, yeah it's true
For the lulz, I try to create E class which extends D and stdclass classes and get error!
php > class E extends D, stdclass{};
PHP Parse error: syntax error, unexpected ',', expecting '{' in php shell code on line 1
Parse error: syntax error, unexpected ',', expecting '{' in php shell code on line 1
Multiple inheritance is not possible in PHP like in many OOP supported languages
See similar topic here. The topic is in AS3 but gives you answer.
To answer particularly about solving using interfaces is answered in the same post here
As told here by #tonicospinelli, it seems that indeed, PHP allows multiple inheritance of interfaces, but it isn't clearly explained, just given an example
The way multiple inheritance works, PHP passes these using Traits that implement Interfaces.
Once you declare a Class implementing a "multi-interface" (1), you may use already defined Traits to assure inheritance is well-performed.
(1): Saying "multi-interface" I mean a class implementing an interface what extends from multiple other interfaces

How to work with PHP abstract?

Why would you use such abstract? Does it speed up work or what exactly its for?
// file1.php
abstract class Search_Adapter_Abstract {
private $ch = null;
abstract private function __construct()
{
}
abstract public funciton __destruct() {
curl_close($this->ch);
}
abstract public function search($searchString,$offset,$count);
}
// file2.php
include("file1.php");
class abc extends Search_Adapter_Abstract
{
// Will the curl_close now automatically be closed?
}
What is the reason of extending abstract here? Makes me confused. What can i get from it now?
You can use abstract classes to define and partially implement common tasks that an extended class should do. Since explaining it is difficult without an example, consider this:
Without abstract classes, you would have to define two basic classes with the same methods and implementation. Since OOP is all about preventing code duplication, this is quite wrong:
class Car {
public $brand = 'mercedes';
public function gasPerMile($weight)
{
// Useless calculation, purely for illustrating
$foo = $weight * 89 / 100;
return $foo;
}
public function carSpecificFunction()
{
// Only present in class Car
}
}
class Truck {
public $brand = 'MAN';
public function gasPerMile($weight)
{
// Useless calculation, purely for illustrating
$foo = $weight * 89 / 100;
return $foo;
}
public function truckSpecificFunction()
{
// Only present in class Truck
}
}
Now you have some common properties and methods, which are duplicated in two classes. To prevent that, we could define an abstract class from which Car and Truck are extended. This way, common functionalities are kept in one place and the extended classes will implement specific properties and methods for either the Truck or the Car.
abstract class Vehicle {
abstract public $brand;
public function gasPerMile($weight)
{
// Useless calculation, purely for illustrating
$foo = $weight * 89 / 100;
return $foo;
}
}
This way, you ensure that atleast every class that extends Vehicle has to have a brand specified and the common gasPerMile() method can be used by all extended classes.
Of course, this is a simple example, but hopefully it illustrates why abstract classes can be useful.
So you can implement different Search adapters and all of them must implement that search method. See inheritance here.
Basically what you get is that every class extending "Search_Adapter_Abstract" can be used as a Search Adapter. The behaviour changes (because the method search is implementend differently) but you guarantee the "search" method is there with that signature.
This isn't going to be a popular answer, but still...
abstract, interface, private and other keywords, borrowed from Java, are elements of cargo cult programming and serve no real purpose in PHP, except to make the author appear more "serious" and "professional".
Explanation: these keywords are compile-time contracts, that have no effect on how your program runs and only meant as an aid for a compiler... assuming you have one. In a compiled language, like Java or C#, you physically cannot deploy a program that violates a contract, e.g. doesn't implement an abstract method. You simply don't get it compiled. This is a Good Thing, because you can fix some kinds of bugs very quickly, without testing and debugging.
PHP, on the contrary, doesn't have a compiler, and performs all contract checks at run time. This is a Bad Thing, because you need to test and debug to find contract violations manually. Consider the following:
class Abs {
abstract function implementMe();
}
if ($_GET['x'] == 'foo')
include "GoodClass.php";
if ($_GET['x'] == 'bar')
include "BadClass.php";
where "BadClass" extends "Abs", but doesn't implement "implementMe" method. This script can be deployed and will run just fine until someone calls it with "?x=bar" and then - bang! - your program suddenly crashes. To make the things worse, this will be a "fatal" error, so that you won't be even able to handle it in a reasonable way.
That is, abstract and friends are not only useless, but also quite harmful in PHP. Not only they don't help you with bug hunting, but also they are potential source of even more glitches. Stay away.

Categories