OO Design issues

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
vigge89
Forum Regular
Posts: 875
Joined: Wed Jul 30, 2003 3:29 am
Location: Sweden

OO Design issues

Post by vigge89 »

I just ran into a couple of problems while starting to practice with OOP, consider the following code:

Code: Select all

class db {
    function query($sql) { ... }
}

class second_class {
    var $third_class;
    function second_class() {
        $this->third_class= new third_class();
    }
    function someFunction ($vars) {
        // do some queries
        $db->query("UPDATE ....");
   }
}

class third_class{
    function doSomething($something) {
        // lines of code
        if (is_file($something))
                $data = file_get_contents ($something)
        else
                $query = $db->query("SELECT * FROM table WHERE id='$something'");
                $data = $query->fetch();
        // lines of code
    }
}

$db = new db();
$class = new second_class();
$class->third_class->doSomething();
First, how am I supposed to create a relation between the db class and the second_class (an instance of db will be required for second_class to operate, and will often be used by third_class), should I create an instance of db inside the second_class or outside it in the global scope, and how would I call it "correctly" from both the second and third classes? In the third_class, should I check if $db has been instanced and proceed with querying it if it has, and if so, how would I do this?

I've been looking around the web and on PHPDN but have had a hard time finding resources (articles/guides/etc.), so if anyone of you have some good links, I'd be happy to take a look.
User avatar
superdezign
DevNet Master
Posts: 4135
Joined: Sat Jan 20, 2007 11:06 pm

Post by superdezign »

Code: Select all

class FirstClass
{
    function Query($sql);
}

class SecondClass
{
    var $pFirstClass;

    function SecondClass($pFirstClass)
    {
        $this->pFirstClass = $pFirstClass;
    }
}

$first = new FirstClass();
$second = new SecondClass($first);
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

One of the easy ways to determine how to generally couple two classes is to use the "is a" versus "has a."

An example:

"Is class xyz an instance of class abc?" or "Does class xyz have a instance of class abc?"
If the answer is true for the former, it angles toward inheritance. If it's the latter, it points toward composition and usage.
staar2
Forum Commoner
Posts: 83
Joined: Fri Apr 06, 2007 2:57 am

Post by staar2 »

I did not want to make new topic so i few question about PHP 5. What for are interface and abstract? How can i use them and what is their point?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

staar2 wrote:What for are interface and abstract?
Interface define what methods a class must implement. Interfaces contain no code. If the methods are not implemented then you will get an error message, so they inforce a specified interface.

Abstract classes contain code, but cannot be instantiated. They must be extended to create a normal class that can then be instantiated. Usually they contain base functionality, but leave some methods that must be implemented or overridden to create a complete class. So abstract classes force the programmer to finish the class.
staar2 wrote:How can i use them and what is their point?
I would recommend that you do not use them until you find a problem that cannot be solved without them.
(#10850)
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

I've got an issue with abstract class.. In order to use them you have to inherit from to implement the abstract functions...

If you define all the abstract methods in an interface you can implement a regular class that accepts an instance that implements the interface and use that instance in all the places where you need it... This way your implementation can be independant of the class...

eg: (Don't focus on the syntax... I'm getting rusty :p)

Code: Select all

abstract class Foo
{
 abstract something();
}
vs

Code: Select all

class Foo
{
 private ISomething something;

 public Foo(ISomething $something)
 {
  $this->something = $something;
 }
}

interface ISomething
{
 something();
}
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

timvw wrote:I've got an issue with abstract class.. In order to use them you have to inherit from to implement the abstract functions...

If you define all the abstract methods in an interface you can implement a regular class that accepts an instance that implements the interface and use that instance in all the places where you need it... This way your implementation can be independant of the class...
The point of an abstract class it to provide a class of common functions along with customizable functions that vary dependent upon the child class's constraints. Interfaces provide a common guideline of functions that the class must implement, but each implementation, although it may have the same function, requires different code to accomplish.

IE:

Code: Select all

abstract class Drink {
   function pour() {
      return "Man that was a tasty beverage!";
   }
   abstract function Open();
}
public class SodaCan extends Drink {
   function Open() {
      $this->tab->pull();
      return "You've popped the tab on me!";
   }
}
public class WineBottle extends Drink {
   function Open() {
      $this->cork->twist()->pop();
      return "You've popped my cork!";
   }
}
public class myDrink {
    function __construct($drink) {
      echo $drink->Open();
      echo $drink->Pour();
    }
}

$myDrink = new myDrink(new WineBottle());
$myDrink = new myDrink(new SodaCan());
Both WineBottle and SodaCan have a common function that only needs a single codebase to implement, Pour(), which is why it is in the abstract declaration. Open() requires different code to obtain the same result, hence it being declared abstract and needing separate code.

Interface:

Code: Select all

public interface IDrink {
   public function Open();
   public function Pour();
}
public class SodaCan implements IDrink {
   public function Open() {
       $this->tab->pop();
       return "I've been opened!"
   }
   public function Pour() {
       $this->can->grab()->chug();
   }
}
public class WineBottle implements IDrink {
   public function Open() {
       $this->cork->twist()->pull();
       return "I've been popped!";
   }
   public function Pour() {
       $this->bottle->tip();
   }
}
public class myDrink {
    function __construct($drink) {
      echo $drink->Open();
      echo $drink->Pour();
    }
}

$drink = new myDrink(new SodaCan());
$drink = new myDrink(new WineBottle());
Last edited by TheMoose on Tue Jun 05, 2007 2:02 pm, edited 1 time in total.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

Yeah, I prefer interfaces too, but have used abstracts quite successfully in several occasions.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I have only found one or two cases where either interfaces or abstracts actually solved a problem better than not using them. The are really just enforcers and I find that they are very overused. I see programmers create an interface reflexively without ever having a problem enforcing an interface. Call them a Premature De-optimization.
(#10850)
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post by RobertGonzalez »

Man, I am glad someone asked this question. I too was looking at the difference and use cases for interfaces and abstracts. I have been looking at various frameworks and codebases and I see some using them almost everywhere and others using them sparingly.

In my case, I was looking at their place in the View component of MVC and the abstraction layer of DB interaction. But I thought myself a little weird for not using them as much in the framework I am building. Though now, not so much.

I need to hang around T&D more often. These OOP discussions are getting really good as of late.
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

In the central portion of MVC they're not really all that useful. There's not too much of a need to abstract classes outside of views and possibly the DB layer. Unless you plan on switching DB engines constantly, you don't even really need it for that. As for Views, I'd say it's readily useful for creating a common dataset for the view to use, regardless of where you got the data from, either file, logic, or DB.
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

TheMoose wrote:The point of an abstract class it to provide a class of common functions along with customizable functions that vary dependent upon the child class's constraints.
- A major advantage (for me) is the fact that the implementation of the interface does not have to live with a 'IS-A' (name of abstract class).
- The only functional advantage of the abstract class i can imagine is the fact that the concrete implementation can access protected methods.

Eg: As in your example you can have drinks... And in order to consume a Drink a drink would need to know how to open itself... By doing this via abstract methods you implement something that can open drinks and that is a drink itself...

Using interface you can implement a class that is a DrinkOpener (and doesn't have to be a drink itself).

Code: Select all

// about opening a drink
interface IDrinkOpener
{
 function Open();
}

// a drink doesn't have to know how to open itself... That's the task of an IOpener
class Drink 
{
 IDrinkOpener $drinkOpener;

 function Drink(IDrinkOpener $drinkOpener) { $this->drinkOpener = $drinkOpener; }

 // implement functions that use the functionality of a DrinkOpener...
}

// Notice, this class is about the opening of SodaCans... NOT drinks 
class SodaCanOpener : IDrinkOpener
{
 function Open()
 {
  return "You've popped the tab on me'!";
 }
}
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

arborint wrote:I have only found one or two cases where either interfaces or abstracts actually solved a problem better than not using them.
I can imagine that in the context of an average php project they're not really useful (but we already agree on that very long ago ;))

Last year i've been in a situation with teams that actually 'consume services' from each other, and in that situation i've really started to appreciate the advantages of programming against an interface instead of a concrete implementation :)
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post by RobertGonzalez »

@timvw: I think you have been in C# too long. ;)
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

Yes, he's been in the C world a bit ;)

@timvw
The only problem with the IDrinkOpener is that it adds an extra step to handle the opening of the drink. I could see why it could be necessary, as some drinks might implement the same style of opening (say a soda can, and a beer can, or a Heineken mini-keg, etc), vs a wine bottle and a non-alcohol corked bottle, or whatnot.

But with the method you added, you cannot create separate drinks because your Drink class is a single instantiation with concrete methods of its own. You'd have to either make it the parent class and extend children from it if you wanted separate types, ie a Wine Bottle might have different properties and methods than a Soda can does.
Post Reply