Namespaces and abstract class names

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Namespaces and abstract class names

Post by Christopher »

Jenk wrote:The argument is: Composition vs Inheritance.
Actually, I don't think that is the argument. Everyone here agrees that composition is superior. I think the argument is whether (in PHP) that inheritance should ever be used. My conjecture was that there are common use cases where (in PHP) inheritance can do the same thing as composition but with simpler syntax and less work.
(#10850)
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: Namespaces and abstract class names

Post by VladSun »

+120%
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Namespaces and abstract class names

Post by Jenk »

Heh, it's certainly digressed from the original topic anyway :)

But on that note, I try to avoid inheritance where possible.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Namespaces and abstract class names

Post by josh »

@Jonah
Looks like I've gotten sucked into the conversation :)
josh wrote:robot cannot inherit animal because robots aren't organisms! They shouldn't breathe() and sleep()!!! You're going to print_r() your object and get loads of unrelated information. That's a big code smell.
Right. That's a situation where normal inheritance can't cut it, and composition saves the day.
josh wrote:4 ways to define a class in javascript? I know of only one, 'function'.
I think he means like this:

Code: Select all

var MyClass = function () {
    this.something = function () {
         // ...
    }
}
// or
var MyClass = {};
MyClass.prototype.something = function () {
    // ...
}
In javascript there is one way to define a class IMO, which is to create a function with closures. The essence of prototypical inheritance is adding methods to a class after it's defined, I don't really count that as a second method but even if I did that's still not 4 methods ;-)
For one, if you want to name a method the same as a parent class's method, it seems likely that you know it, and want to override it. And two, any IDE can tell you if the method names are in conflict pretty much instantly. Netbeans for example puts a green circle with an "I" in it beside any overriding method.
It seems likely I'll know it? The example I gave was to point out that you may not.
And not any IDE can show you when methods are in conflict. Only netbeans that I know of, and my netbeans project cache always seems to go bad and code completion and the like stop working. I also work with a guy who uses vim, he refuses to use IDEs, you could have team mates like that some day...
So you're saying that we should use 100% composition because we might need what it provides sometime in the future?
I wouldn't say that you should use 100% composition just because you might need it.. I wouldn't go as far as making a hard & fast "rule", however inheritance is a code smell. The further from 100% you get, the less I like your code :-D
Seems like it would be pretty clear cut when a class hierarchy is going to need the functionality that only composition can provide right off the bat.
Well again, objects model concepts in our brain, which don't exist in a hierarchy. While you may be able to implement as a hierarchy at first, there is a high likelyhood of a user request that contradicts that. I don't know about you but I'd rather not tell my customer he has to pay extra for his feature because it doesn't fit into the way I envisioned the objects working a year ago.
And how do abstract classes make refactoring difficult?
They don't, but refactoring from an abstract class to composition is easier than just refactoring composition.

@Vlad
You can not argue against abstract classes, saying some features are missing, and then say that implementing these features sucks because their purpose is to serve abstract classes.
I didn't. A virtual method is the same thing as an abstract method, we already have it. It doesn't address any of the problems with abstract classes, it just encourages programmers to use more abstract classes (making their inherent problems more rampant!). If one of the things you listed means the same as prototypical inheritance then that one I'd be in favor of. In prototypical inheritance there are NO abstract classes though, I am AGAINST abstract classes.
Christopher wrote:I think the argument is whether (in PHP) that inheritance should ever be used. My conjecture was that there are common use cases where (in PHP) inheritance can do the same thing as composition but with simpler syntax and less work.
I don't think anyone said it should not be used, I did however say that implementing your code in this way limits your ability to add certain features in the future. Its the same as global variables, static code, or singletons. They have a use and they also have drawbacks. There are also alternative ways to structure your code that have the same uses with less drawbacks. Hence why more experienced programmers recommend staying away from those particular features.

@Jenk
Heh, it's certainly digressed from the original topic anyway
In the same way your code needs to digress from a strict hierarchy sometimes your thread has to digress. lol. I'd be against splitting the thread though, unless the OP requests it.
But on that note, I try to avoid inheritance where possible.
I'd agree except for the "where possible", that implies inheritance is needed, which it is not :-D Wanted? Sure. Needed? No. I have a need for objects because I can't structure code w/o them, there is no physical way to do it. I only "want" inheritance though, I don't need it.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Namespaces and abstract class names

Post by Jenk »

I meant in cases where it is not in my control :) I work fulltime with .NET now, and Inheritance is rife in the various frameworks.
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: Namespaces and abstract class names

Post by Eran »

How about the following example for database abstraction (which I'm sure you're familiar with) - you want to support multiple databases but have the same interface. The usual approach is to create an abstract class that defines interface methods (such as query(), connect() and quote() etc) and extend it for the specific database vendors. How would you implement it better using composition instead of inheritance?
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Re: Namespaces and abstract class names

Post by Weirdan »

Eran wrote:How about the following example for database abstraction (which I'm sure you're familiar with) - you want to support multiple databases but have the same interface.
As long as no implementation inheritance is needed simple interface would suffice.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Namespaces and abstract class names

Post by josh »

You'd break out interfaces. For example maybe before a query we have to describe some fields, and the way we do that varies depending on the driver. I actually thought of this earlier and figured someone would ask.

Code: Select all

// the only abstraction we do is to define our interface 'abstracly'
interface Db
{
 function __construct(Db_Field_Describer $fieldDescriber );
 function query();
 function describeFields();
}

interface Db_Field_Describer
{
 function describeThoseFields();
}

// the mysql "aspects" of the program:

class Db_Mysql impelements Db
{
}

class Db_Mysql_Field_Describer implements Db_Field_Describer
{
}

// the SQL lite "aspects" of the program

class Db_SQLLite implements Db
{
}

class Db_SQLLite_Field_Describer implements Db_Field_Describer
{
}
For the parts that must vary (describing fields) you move it to another component & polymorphism takes over. Now people can use the "describer" even if their class isn't part of the DB package. All our method's are public and it obeys the single responsibility principle. Each responsibility is in a stand alone component that is not coupled to a bunch of other bloated code. To the person who just wants to describe fields, being able to call query() is just a distraction & would be regarded as bloat. These benefits sound cheesy for something like a database, but I'm sure you see the benefit.

Basically instead of separating at the method level, I'm saying the future will be in separating at the class level :-D (at least for those of us still living in the past). Its very likely describing those fields may take 20 other methods. Maybe one that sends the query, another method for parsing the string mysql sends back. Another method for breaking it out into an array, etc. Those could be public methods on the "describer" object. Heck, some of those methods could eventually become their own class if your database framework was really complicated.

One thing you may say is theres too many interfaces & classes, but each is in it's own file. You usually don't look at all of them at once. With an abstract class though, you have all of the methods for all of those classes in one big list. What could be worse as far as following single responsibility principle?

Code: Select all

interface Db_Mysql
{
 function describeFields();
 protected function describeFieldsParseResults();
 protected function describeFieldsExplodeResults();
 function query();
 protected function doQuery();
}
See, the above is the style that abstract classes can promote. A bunch of unrelated concerns in one big "god" interface, its a mess to read IMO, especially when your IDE decides to show it in alphabetical order. With composition, if my IDE put the methods in alphabetical order I'd thank the IDE, with an abstract class you may just end up cursing your IDE.
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: Namespaces and abstract class names

Post by Eran »

If you only use interfaces, then you'll be repeating a lot of code - queries on SQL databases are very similar with only minor variations and so are connections and configuration (at least from the PHP side). I'd put some implementation for the general use-cases in the abstract Db class and override only when necessary (which isn't that often).
User avatar
Jonah Bron
DevNet Master
Posts: 2764
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: Namespaces and abstract class names

Post by Jonah Bron »

Eran wrote:If you only use interfaces, then you'll be repeating a lot of code - queries on SQL databases are very similar with only minor variations and so are connections and configuration (at least from the PHP side). I'd put some implementation for the general use-cases in the abstract Db class and override only when necessary (which isn't that often).
Good point Eran. But I think I can answer it for Josh :) You'd create another class like this:

Code: Select all

class DbConnection {
    private $dbStrategy;
    _construct(Db $strategy) {
        $this->dbStrategy = $strategy;
    }
    // logic common to all databases here
}
// usage
$db = new DbConnection(new Db_Mysql());
And use that instead of directly using Db implementations.
josh wrote:One thing you may say is theres too many interfaces & classes, but each is in it's own file. You usually don't look at all of them at once. With an abstract class though, you have all of the methods for all of those classes in one big list. What could be worse as far as following single responsibility principle?
Doesn't that seem a little extreme though? You could take it farther and continue to break it down to the very lowest level.
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: Namespaces and abstract class names

Post by Eran »

Good point Eran. But I think I can answer it for Josh :) You'd create another class like this:
And use that instead of directly using Db implementations.
It's not just connections, it's also queries and configuration. How do you account for the small differences between database vendors without ending up with a ton of tiny classes that each has one method or two? to me that sounds harder to maintain then just using a base abstract class that implements that common functionality. Not saying you can't do it, but for this purpose it seems like composition is being forced on principle when it doesn't make things simpler or better.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Re: Namespaces and abstract class names

Post by Jenk »

Have a look at the Hibernate project in Java for an example of how exactly that is done. There are IConnection, IQuery, IConfiguration interfaces, and implementations there of for the multitude of supported DB engines.

Already in the post asking What to do with different DBs you've listed a number of roles that, in your example, should be maintained by a single object - this is wrong. Each of those roles should be maintained by separate objects, and kept in a composite.
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: Namespaces and abstract class names

Post by Eran »

this is wrong
That's like, your opinion, man ;)

Seriously though, you can't say that is "wrong" - it is just different from the way you do it. You'll need to be more elaborate on why you think each simple operation needs its own class as opposed to being a method on a class that binds those operations together.
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: Namespaces and abstract class names

Post by VladSun »

Code: Select all

interface ICount
{
	public function one($param);
	public function all($param);
}

interface IOrder
{
	public function one($param);
	public function two($param);
}

class AClass implements \ICount, \IOrder
{
	public function one($param1)
	{
		echo 'one: ' . $param;
	}

	public function two($param)
	{
		echo 'two: ' . $param;
	}
}
[text] Fatal error: Can't inherit abstract function IOrder::one() (previously declared abstract in ICount) in /www/site/draft/1/2.php on line 16[/text]
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
Jonah Bron
DevNet Master
Posts: 2764
Joined: Thu Mar 15, 2007 6:28 pm
Location: Redding, California

Re: Namespaces and abstract class names

Post by Jonah Bron »

Eran wrote:It's not just connections, it's also queries and configuration. How do you account for the small differences between database vendors without ending up with a ton of tiny classes that each has one method or two? to me that sounds harder to maintain then just using a base abstract class that implements that common functionality. Not saying you can't do it, but for this purpose it seems like composition is being forced on principle when it doesn't make things simpler or better.
Hey, I didn't say that was the best way to do it :wink: . But I really can't say either way. An abstract class makes more sense to me in this case though.
Post Reply