Classes interfacing in PHP

  • MasterZ
  • Expert
  • Expert
  • User avatar
  • Posts: 699
  • Loc: Colorado Springs

Post 3+ Months Ago

Hey guys,

As several of you know I'm a veteran to PHP but I'm just now trying to learn the OOP side of it (I know, about time, huh?).

I've got a lot of the basics down but was wondering if I have 2 different classes, can a function inside one class make use of a function in another class or does something special have to happen first?

Thanks.

- Jon
  • Anonymous
  • Bot
  • No Avatar
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post 3+ Months Ago

  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

If both classes will share a few properties and/or methods that would be otherwise useless by themselves, you can stick all of those common members in an Abstract Base Class and have both of your classes extend that base class.

Unless I misunderstand what you mean by "making use of" functions. :)
  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8388
  • Loc: USA

Post 3+ Months Ago

:lol: No matter how many articles on abstract classes and examples I read, I can't grasp them :banghead:
  • MasterZ
  • Expert
  • Expert
  • User avatar
  • Posts: 699
  • Loc: Colorado Springs

Post 3+ Months Ago

An example that I'm thinking of (although have not tried yet), say I have a game, with 2 classes. 1 is the database access, the other is the character. Could I have a character method (ex. $character->add_exp(10)) use the database method (ex. $db->query('update character set exp = exp+10 where id = 1'))?

Is there anything that I need to do to make these classes talk to eachother or can I just do it like that?

Thanks. :)

Please forgive any sql syntax errors, it's just a quick example
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

Code: [ Select ]
class db {...}
class utilizes_db
{
public function add_exp($exp)
{
     global $db;
     $db->query(...);
}
}
$db = new db();
$obj = new utilizes_db();
$obj->add_exp(10);
  1. class db {...}
  2. class utilizes_db
  3. {
  4. public function add_exp($exp)
  5. {
  6.      global $db;
  7.      $db->query(...);
  8. }
  9. }
  10. $db = new db();
  11. $obj = new utilizes_db();
  12. $obj->add_exp(10);
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6247
  • Loc: Seattle, WA

Post 3+ Months Ago

You need to learn more about object-oriented programming before you can begin to learn and use classes properly. You can't just start sticking variables and functions in classes and call it object-oriented, it doesn't work that way.

http://staffweb.londonmet.ac.uk/~chalkp ... cepts.html
http://www.aonaware.com/OOP1.htm
  • MasterZ
  • Expert
  • Expert
  • User avatar
  • Posts: 699
  • Loc: Colorado Springs

Post 3+ Months Ago

I'm trying to learn. I'm completely new at this :D

http://www.killerphp.com has a good introduction to OOP.
  • Nightslyr
  • Proficient
  • Proficient
  • Nightslyr
  • Posts: 283

Post 3+ Months Ago

joebert wrote:
Code: [ Select ]
class db {...}
class utilizes_db
{
   public function add_exp($exp)
   {
      global $db;
      $db->query(...);
   }
}
$db = new db();
$obj = new utilizes_db();
$obj->add_exp(10);
  1. class db {...}
  2. class utilizes_db
  3. {
  4.    public function add_exp($exp)
  5.    {
  6.       global $db;
  7.       $db->query(...);
  8.    }
  9. }
  10. $db = new db();
  11. $obj = new utilizes_db();
  12. $obj->add_exp(10);


:o

If you have to use a raw global, you're doing it wrong.

To the OP, there are a few ways you could do it:

The simplest way would be to create a new database object every time you add the exp. Something like:

Code: [ Select ]
public function addExp($exp)
{
   $db = new Database();
   $db->query(/* the query */);
}
  1. public function addExp($exp)
  2. {
  3.    $db = new Database();
  4.    $db->query(/* the query */);
  5. }


This gets inefficient if there are multiple calls to the function upon each page reload. Also, depending on your design, you'll most likely have several connections to the db at any given time - in the main code, and in the object.

A better way would be to make the database a member of the character object:
Code: [ Select ]
class Character
{
   private $db;
   private $exp;
 
   /* assuming everything is constructed properly */
 
   public function addExp($exp)
   {
      $this->db->query(/* query */);
   }
}
  1. class Character
  2. {
  3.    private $db;
  4.    private $exp;
  5.  
  6.    /* assuming everything is constructed properly */
  7.  
  8.    public function addExp($exp)
  9.    {
  10.       $this->db->query(/* query */);
  11.    }
  12. }


This method has the same potential pitfall of the previous one - the possibility of multiple connections to the db.

That's where a singleton comes in. A singleton is an object that acts like a global, but is safer because it cannot be overridden, and only one may exist at any time. Your database object should be a singleton so all other objects and the main code can use it, as this negates the possibility of multiple connections creeping into your code.

Singletons are simple to create:
Code: [ Select ]
class Database
{
   private static $instance;
 
   private final function __construct(){};
 
   public static function getInstance()
   {
      if(!self::$instance)
      {
         self::$instance = new self();
      }
 
      return self::$instance;
   }
}
  1. class Database
  2. {
  3.    private static $instance;
  4.  
  5.    private final function __construct(){};
  6.  
  7.    public static function getInstance()
  8.    {
  9.       if(!self::$instance)
  10.       {
  11.          self::$instance = new self();
  12.       }
  13.  
  14.       return self::$instance;
  15.    }
  16. }


So now you can simply write:
Code: [ Select ]
public function addExp($exp)
{
   $db = Database::getInstance();
   $db->query(/* query */);
}
  1. public function addExp($exp)
  2. {
  3.    $db = Database::getInstance();
  4.    $db->query(/* query */);
  5. }
  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8388
  • Loc: USA

Post 3+ Months Ago

@Nightslyr: Or you can do what I do... check if the database is connected, and if it is, don't connect.

Code: [ Select ]
<?php
function connect($dbname = null)
{
    // Checking if we are already connected to MySQL
    if(is_resource($this->mysql_link) || @mysql_ping($this->mysql_link))
    {
        return true;
    }
   
    // Connecting to MySQL
    if($this->persistant)
    {
        // Persistant connect
        $this->mysql_link = @mysql_pconnect($this->host, $this->user, $this->pass);
    }
    else
    {
        // Normal Connect
        $this->mysql_link = @mysql_connect($this->host, $this->user, $this->pass);
    }
   
    // If we are still not connected, then die with some debugging script
    if(!is_resource($this->mysql_link))
    {
        die($debug);
    }
   
    // Selecting the Database
    $this->dbselect($dbname);
}
?>
  1. <?php
  2. function connect($dbname = null)
  3. {
  4.     // Checking if we are already connected to MySQL
  5.     if(is_resource($this->mysql_link) || @mysql_ping($this->mysql_link))
  6.     {
  7.         return true;
  8.     }
  9.    
  10.     // Connecting to MySQL
  11.     if($this->persistant)
  12.     {
  13.         // Persistant connect
  14.         $this->mysql_link = @mysql_pconnect($this->host, $this->user, $this->pass);
  15.     }
  16.     else
  17.     {
  18.         // Normal Connect
  19.         $this->mysql_link = @mysql_connect($this->host, $this->user, $this->pass);
  20.     }
  21.    
  22.     // If we are still not connected, then die with some debugging script
  23.     if(!is_resource($this->mysql_link))
  24.     {
  25.         die($debug);
  26.     }
  27.    
  28.     // Selecting the Database
  29.     $this->dbselect($dbname);
  30. }
  31. ?>


Also, read this post onward... according to Joebert, you're not supposed to have the __construct(); private.
  • Nightslyr
  • Proficient
  • Proficient
  • Nightslyr
  • Posts: 283

Post 3+ Months Ago

Will that work for multiple db objects? As in:

Code: [ Select ]
$db1 = new Database();
$db2 = new Database();
 
$db1->connect(/* some db name */);
$db2->connect(/* same name */);
  1. $db1 = new Database();
  2. $db2 = new Database();
  3.  
  4. $db1->connect(/* some db name */);
  5. $db2->connect(/* same name */);


From what I can see, unless $mysql_link is set in the constructor, hard coded when the data member is declared, or declared as static, the initial comparison will always fail as $mysql_link will be null until that object connects to the db.

EDIT: I don't agree with Joebert. I'd much rather use a singleton than hope that someone made sure to name the globally-linked variable correctly (let alone accidentally overwriting it or deleting it). Not to mention the use of the global keyword breaks encapsulation, as someone using the class needs to know how a class member is named before they can use the class properly.

Globals are bad regardless, but if you're going to use them, you might as well be safe with them. I'd gladly sacrifice the constructor from my object's public interface to do so.
  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8388
  • Loc: USA

Post 3+ Months Ago

I don't know if that would do that... I use globals for my site and there is no problem with them that I see... it actually helps me organize the coding quite a bit.
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

Quote:
If you have to use a raw global, you're doing it wrong.


Yeah because having a bathroom in every room of your house is just such a good idea. :roll:
  • Nightslyr
  • Proficient
  • Proficient
  • Nightslyr
  • Posts: 283

Post 3+ Months Ago

joebert wrote:
Quote:
If you have to use a raw global, you're doing it wrong.


Yeah because having a bathroom in every room of your house is just such a good idea. :roll:


:roll:

Using the 'global' keyword is the antithesis of OOP. Objects should not need to have intimate knowledge of the code that uses them, and the main code should not need to know how the internals of an object work. What matters is the interface. Objects should have a clearly defined public interface that the main code uses to communicate with the objects in order to perform operations. If something from the main code needs to be worked on by the object, then it should be passed as an argument into that method.

Raw globals are dangerous because they promote tight coupling and can be overridden at any time. This makes code harder to debug and less modular. That is why globals should be avoided. However, if it is determined that using a global is the only or best way to solve a problem, then a singleton mitigates some of the negatives a raw global has. An even better solution would be to create what someone else termed a Singlestantiator:
Code: [ Select ]
class Singlestantiator
{
   private static $instantiated = false;
 
   public function __construct()
   {
      if(self::$instantiated == true)
      {
         throw new Exception("Can only have one");
      }
 
      self::$instantiated == true;
   }
}
  1. class Singlestantiator
  2. {
  3.    private static $instantiated = false;
  4.  
  5.    public function __construct()
  6.    {
  7.       if(self::$instantiated == true)
  8.       {
  9.          throw new Exception("Can only have one");
  10.       }
  11.  
  12.       self::$instantiated == true;
  13.    }
  14. }


And pass it by reference to other objects.

Now, if you want to use the 'global' keyword, go ahead. But to imply it as good practice inside of an OOP thread is laughable.
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6247
  • Loc: Seattle, WA

Post 3+ Months Ago

Nightslyr, if this were Reddit, I'd upvote your post.

Post Information

  • Total Posts in this topic: 14 posts
  • Users browsing this forum: No registered users and 85 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
cron
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.