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
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 »

Wait, so the walk strategy keeps track of the leg state, not the Dog/Robot?
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 »

Yep, the Strategy object should not know anything about its owner/master
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 »

Ah, I see.

So what about an obvious situation for an abstract class, like the Db library I linked to? Would an abstract class be better in that situation? Or is that subjective?
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 »

While I agree that interfaces + composition + DI does what inheritance does, plus adds some nice functionality for mixins, multiple inheritance, etc. However, I want to temper Josh's ooh-aah presentation with the fact that (in PHP) simple inheritance solve a lot of common use cases in a very simple way. I advocate composition over inheritance, but I also think people like the Javascript guys have convinced themselves that inheritance is bad because they don't have it.

As an analogy, you could by a car that has an engine included (inherited), or you could by a car that comes with an Engine Injector that creates and puts a new engine into the car every time you want to drive it. Yes, they do the same things. And yes, the Engine Injector potentially could do some cool stuff. But on some level you are just doing more work for the same result.
(#10850)
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 »

So it's like everyone has said so far: composition is good sometimes, and inheritance is good sometimes.

That's interesting Christopher: composition may help us a lot working on <whisper>ProjectX</whisper> *wink wink*
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 »

Christopher wrote:As an analogy, you could by a car that has an engine included (inherited), or you could by a car that comes with an Engine Injector that creates and puts a new engine into the car every time you want to drive it. Yes, they do the same things. And yes, the Engine Injector potentially could do some cool stuff. But on some level you are just doing more work for the same result.
A better analogy is with the inheritance car, to replace the engine you have to replace every other part.
With the composition car every part is interchangeable on it's own.

"injecting" the engine into the car would not be done by the person using the car, probably it would be done at the factory (some soft of factory object)! It would only need be done once, not every time you instantiate it. You create that factory 1x only and use it millions of times, you don't ever need to worry about the engine again, until you want to.

Although I did say inheritance does provide simpler code, obviously simple is subjective but I see it this way: not having a factory is simpler than having one. However being able to change your engine out easily is also simpler than having to refactor an abstract class. So again, its really subjective. I think what is more objective is composition has more propensity for writing complex programs that follow good practices. Inheritance eventually has to break down, eventually the programmer will put walk(), breathe() & kill() all in one super class, or will duplicate the walk() method. (mixing the responsibilities of animals/robots. That part is objective.

Note though, I'm comparing one vs the other. Nothing wrong with using both on the same project, Nothing "wrong" with inheritance either per se. Its just less robust than composition, therefore lower learning curve.
Jonah Bron wrote:Wait, so the walk strategy keeps track of the leg state, not the Dog/Robot?
Either way. The walk strategy could hold a reference back to it's master, but typically would not.
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 »

The car analogy is inaccurate. The Car is "instantiated" once at the Car Factory. The engine is injected, along with the other component parts.

The car doesn't get garbage collected when you park it in your garage at night, it still sits there, ready to be driven again the next day.

The other major difference between inheritance and composition is inversion of control. In inheritance, the child class must know what the parent class does, and how it does it (i.e. implementation - violating black-box!) but in composition, the compositing class only needs to know the interface of its dependencies, it doesn't need to know implementation, and the dependency doesn't need to know anything about the classes it will be used in. Indeed it doesn't even know which classes it will be used in.

Also on the animal/walk example. What if, at runtime, we decide that the 4 legged animal suddenly grows an extra pair of legs? We can inject a different "Walker" object. If we were using inheritance, that can't happen and we'd need to change code to break the inheritance tree.
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 »

Dependency injection is a different topic from composition.

The ability to inject an engine into your car doesn't rule out the car giving itself a default engine. Whether the car sets it's own engine or a factory does it, is irrelevant (to this discussion at least). As long as its collaborating with another object, instead of with a super-class. Your object could grab the strategy from a global variable, it's not advisable but its still composition.

Aside from using a factory to instantiate it, there is no difference to the user of the class. I think its accurate. "buying the car" from the factory in real life is analogous to "writing the code for the factory class" in your program. You only do it once. From then on out you just take the factory object and ask for your car. (The fact its injecting an engine isn't of any importance really...).

Composition + Inheritance on same project = You can follow the single responsibility principle
Inheritance only = You cannot follow the single responsibility principle.
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 »

Jenk wrote:Or get rid of the "abstract" bit of it, and use it as a composite in all "child" classes :mrgreen:

I am seriously of the opinion these days that abstract classes are foul, and the only thing that should ever be abstracted is an interface (which is redundant in PHP anyway, as of course it is dynamic - happy days!)

Code: Select all

class Object_Abstract
{
	public function setup($config)
	{
		foreach ($config as $property => $value)
		{
			if (property_exists($this, $property))
			{
				$this->{$property} = $value;
			}
			else
			{
				throw new \InvalidArgumentException('Property ('.$property.') does not exist.');
			}
		}
	}
}
And I'm pretty sure what you will say - "don't use protected/private" :)
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 »

That's a bit of an interesting example. The usage seems to be something like:

Code: Select all

$config = array("foo" => "bar", "baz" => "blah");
$something = new Something();
$something->setup($config);
Why not just:

Code: Select all

$something = new Something();
$something->foo = "bar";
$something->baz = "blah";
or better yet:

Code: Select all

$something = new Something("bar", "blah");
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 »

as for DI being a separate topic, yes it is, but if using Inheritance, there is no possible way to change the dependency without changing the inheritance tree. The point I was getting at, is that it is bad practice to depend on implementation (something you must and can only do with Inheritance) vs depending only on the role/interface which allows anything that implements that role/interface to be used.
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 »

Jenk wrote:Why not just:

Code: Select all

$something = new Something();
$something->foo = "bar";
$something->baz = "blah";
$foo and $bar may be private/protected.

A better "setupable" object would be:

Code: Select all

class Object_Abstract
{
        public function setup($config)
        {
                foreach ($config as $property => $value)
                {
                        if (method_exists($this, 'set' . ucfirst($property)))
                        {
                                $this->{'set' . ucfirst($property)}($value);
                        }
                        elseif (property_exists($this, $property))
                        {
                                $this->{$property} = $value;
                        }
                        else
                        {
                                throw new \InvalidArgumentException('Property ('.$property.') does not exist.');
                        }
                }
        }
}
Jenk wrote:or better yet:

Code: Select all

$something = new Something("bar", "blah");
We had a related discussion here:
viewtopic.php?f=19&t=126953

Also :

Code: Select all

        public function setup($config)
        {
                ...
                $this->fireEvent('reconfigured', $this, $config);
        }
There are 10 types of people in this world, those who understand binary and those who don't
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 other major difference between inheritance and composition is inversion of control. In inheritance, the child class must know what the parent class does, and how it does it (i.e. implementation - violating black-box!) but in composition, the compositing class only needs to know the interface of its dependencies, it doesn't need to know implementation, and the dependency doesn't need to know anything about the classes it will be used in. Indeed it doesn't even know which classes it will be used in.
I think these statements are erroneous. First, Inversion of Control and black-box are two different things that you conflate here.

Second, a child class need not know any more about methods it inherits than the interface. This is no different than what is known about a method in a composited object. You can choose to look at the source of either or not. You can choose to use or replace the methods of either, or not. You don't know anything about the implementation of PHP's many built-in classes, yet can happily extend them knowing only their interfaces. Similarly, a class can be provided access to the properties of both inherited classes and composited objects, or not.

My point above was only that for many common use cases inheritance is the simplest solution -- involving only two additional words in a class file.
(#10850)
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 knew that would happen, I'm not talking of "Inversion of Control" (i.e. "Dependency Injection") I'm stating the the control of what is implemented is inverted (i.e. the literal meaning of the control has been inverted :P) in that the "parent" becomes the "child"/dependent.
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 »

Subclasses do know their superclass' implementation. Try to have both classes use variables & methods with the same name, you don't have to worry about that crap if you don't use inheritance :-D

@Vlad, OK, but you could have a class called Config and just pass the whole config object. All that logic would live in only the config class, instead of asking your compiler to make it available globally on all classes. When classes need to be configured they collaborate with a config object, or the config object collaborates with them. Either the config object can be injected into the "main object". Or the config object could be passed an instance to the "main object", and would subsequently call a bunch of setter commands on the "main object" to set it up. Your config objects would be like data mappers.

The problem with your abstraction, again, is you may have classes that need to implement it differently. You did conjure up a low risk example of using abstraction but I'm sure I still see risk in coding that way.
Post Reply