473,396 Members | 1,972 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

PHP OO - How to use a class within another class?

88
Hi,

Im just learning OO in PHP and not sure the best method to use the functions for example in a database wrapper class within another class for example which handles all user authentication. I have put together this test code of how I am currently implementing it:

Expand|Select|Wrap|Line Numbers
  1. <?
  2. class DB
  3. {
  4.   public function __construct($host,$user,$pass,$dbname)
  5.   {
  6.     mysql_connect($host,$user,$pass)
  7.       or die(mysql_error());
  8.     mysql_select_db($dbname)
  9.       or die(mysql_error());
  10.   }
  11.   public function qry($sql)
  12.   {
  13.     return mysql_query($sql)
  14.       or die(mysql_error());
  15.   }
  16. }
  17.  
  18. class User
  19. {
  20.   public $user_id;
  21.   public function __construct($user_id)
  22.   {
  23.     $this->user_id = $user_id;
  24.   }
  25.   public function update_user()
  26.   {
  27.     global $db;
  28.     $db->qry(" UPDATE users SET active = 1 
  29.       WHERE user_id = '" . $this->user_id . "' ");
  30.   }
  31. }
  32.  
  33. $db   = new DB("localhost","root","","test_database");
  34. $user = new User(2);
  35.  
  36. $user->update_user();
  37. ?>
Is that use of global considered bad practice? I was browsing the source of PHPBB3 and they use the global method when accessing its database class from other classes however I believe I can instead pass a reference to the object via a param so would that method be better? If someone could give me a few pointers it would be appreciated.

Cheers.
Apr 4 '09 #1
8 22805
Markus
6,050 Expert 4TB
Have a database property for your User class.

Expand|Select|Wrap|Line Numbers
  1.  
  2. class DB {
  3.  
  4.    // ...
  5.  
  6. }
  7.  
  8. class User { 
  9.  
  10.     private $_db;
  11.  
  12.     public function User ( ) 
  13.     {
  14.         $this->_db = new DB;
  15.     }
  16.  
  17. }
Apr 5 '09 #2
hoopy
88
Hi Markus,

Thanks for the response, however I do have a question.

The __construct() for the DB class opens the connection from the login parameters passed. Therefore with your method I need to have the login details hard coded into the USER class itself rather than in the code which creates the instances.

Is this the standard practice for using classes within classes? Can you see my problem and advise of a possible workaround?

Thanks.
Apr 5 '09 #3
Dormilich
8,658 Expert Mod 8TB
a common practice for DB classes is implementing the Singleton pattern (which can also hold the DB access data (maybe coded through constants)

the User class doesn't need to pass DB data, unless you want to (be able to) connect to different databases.
Apr 5 '09 #4
hoopy
88
Thanks Dormilich.

I checked out about the Singleton pattern, follows some tutorials and came up with this which works well in that it only calls the database connection once and I can use that class within any other classes, here is my example code:

Expand|Select|Wrap|Line Numbers
  1. <?
  2. class DB
  3. {
  4.   private static $dbInstance;
  5.  
  6.   public function __construct($host,$user,$pass,$dbname)
  7.   {
  8.     echo("Would have connected to " . $host . " DB.<br />");
  9.   }
  10.  
  11.   public static function getInstance($host=null,$user=null,
  12.     $pass=null,$dbname=null)
  13.   {
  14.     if (!self::$dbInstance)
  15.     {
  16.       self::$dbInstance = new DB($host,$user,$pass,$dbname);
  17.     }
  18.     return self::$dbInstance;
  19.   }
  20.  
  21.   public function qry($sql)
  22.   {
  23.     echo("Would have executed: " . $sql . "<br />");
  24.   }
  25. }
  26.  
  27. class User
  28. {
  29.   private $db;
  30.   public function __construct()
  31.   {
  32.     $this->db = DB::getInstance();
  33.   }
  34.   public function SelectUsers()
  35.   {
  36.     $this->db->qry(" select * from users ");
  37.   }
  38. }
  39.  
  40. class News
  41. {
  42.   private $db;
  43.   public function __construct()
  44.   {
  45.     $this->db = DB::getInstance();
  46.   }
  47.   public function SelectNews()
  48.   {
  49.     $this->db->qry("select * from news");
  50.   }
  51. }
  52.  
  53. $dbc = DB::getInstance("localhost", "root", "", "test_database");
  54. $usr = new User();
  55. $usr->SelectUsers();
  56. $usr->SelectUsers();
  57. $nws = new News();
  58. $nws->SelectNews();
  59. $usr->SelectUsers();
  60. ?>
This will produce the following output:

Expand|Select|Wrap|Line Numbers
  1. Would have connected to localhost DB.
  2. Would have executed: select * from users
  3. Would have executed: select * from users
  4. Would have executed: select * from news
  5. Would have executed: select * from users 
So you can see it only connects once which is great and I dont need to provide DB login details within any of the classes.

Thanks for everyones help.

Cheers.
Apr 6 '09 #5
Dormilich
8,658 Expert Mod 8TB
[EDIT] Unfortunately, you got the Singleton Pattern wrong. what about
Expand|Select|Wrap|Line Numbers
  1. $a = new DB(…);
  2. $b = new DB(…);
?

you must leave the __construct() and __clone() methods empty in a Singleton pattern! (OK, you may throw an Exception or leave a note)

you can also try to pass the DB parameters via static properties.

Expand|Select|Wrap|Line Numbers
  1. require "db.config.php";
  2.  
  3. class DB
  4. {
  5.   private static $dbInstance = NULL;
  6.   public static $host;
  7. // or using a default value via constants
  8. // public static $host = DB_DEFAULT_HOST;
  9.   public static $user;
  10.   public static $pass;
  11.   public static $dbname;
  12.  
  13.   public function __construct()  {  }
  14.  
  15.   public function __clone()  {  }
  16.  
  17.   public static function getInstance()
  18.   {
  19.     if (self::$dbInstance === NULL)
  20.     {
  21.       self::$dbInstance = new self;
  22.       self::connect();
  23.     }
  24.     return self::$dbInstance;
  25.   }
  26.  
  27.   private static function connect()
  28.   {
  29.     # do DB connection here
  30.   }
  31. }
  32.  
  33. // optional if you use your defaults
  34. DB::$host = "localhost";
  35. DB::$user = "****";
  36. DB::$pass = "****";
  37. DB::$dbname = "my_db_name";
  38. $dbc = DB::getInstance();
  39.  
Apr 6 '09 #6
hoopy
88
Dormilich, thanks for that clarification.

I have implemented what you desribed and its working fine.

Thank you.
Apr 7 '09 #7
Dormilich
8,658 Expert Mod 8TB
I'm glad I could be of help.

OOP rulez.

@Dormilich
incorrect, but I noticed that way too late.
Apr 7 '09 #8
Dormilich
8,658 Expert Mod 8TB
just for additional information a Singleton like DB class using PDO

Expand|Select|Wrap|Line Numbers
  1. // used for connecting to MySQL
  2. // stores the Prepared Statements
  3.                              (the interface, so that all DB_User classes 
  4.                               can safely call the methods)
  5. abstract class DB implements DB_connector
  6. {
  7.     /* PDO instance */
  8.     private static $PDO = NULL;
  9.  
  10.     /* collection of Prepared Statements */
  11.     private static $PS = array();
  12.  
  13.     /* DB name to set up */
  14.     public static $dbname = DB_DEFAULT_NAME;
  15.  
  16.     /* close DB connection on script end */
  17.     function __destruct()
  18.     {
  19.         self::$PDO = NULL;
  20.     }
  21.  
  22.     /* create a single instance of PDO */
  23.     public static function connect()
  24.     {
  25.         if (self::$PDO === NULL)
  26.         {
  27.             try {
  28.                 // server, login & password hardly ever change in a project
  29.                 $dsn = 'mysql:host=' . DB_SERVER . ';dbname=' . self::$dbname;
  30.                 self::$PDO = new PDO($dsn, DB_USER, DB_PASS);
  31.             }
  32.             catch (PDOException $pdo)
  33.             {
  34.                 // any kind of error logging*
  35.                 ErrorLog::logException($pdo);
  36.  
  37.                 // throw Exception so you can safely quit the script
  38.                 $emsg = "MySQL connection failed.";
  39.                 throw new ErrorException($emsg, 500, 0);
  40.             }
  41.         }
  42.     }
  43.  
  44.     /* save the Prepared Statements. I prefer to have them where the
  45.        PDO object is. just personal preference */
  46.     public static function prepare($index, $sql)
  47.     {
  48.         # check if $index already exists (implement your own way)
  49.  
  50.         self::connect();
  51.  
  52.         try {
  53.             self::$PS[$index] = self::$PDO->prepare($sql);
  54.         }
  55.         catch (PDOException $pdo)
  56.         {
  57.             ErrorLog::logException($pdo);
  58.             return false;
  59.         }
  60.         return true;
  61.     }
  62.  
  63.     /* since the Prepared Statements are private, a getter method */
  64.     public static function getStatement($index)
  65.     {
  66.         if (isset(self::$PS[$index]))
  67.         {
  68.             return self::$PS[$index];
  69.         }
  70.  
  71.         // do some error handling here
  72.     }
  73. }
  74.  
  75. * ErrorLog is an Abstract Registry Pattern class that collects caught 
  76.   Exceptions (and is able to display them later)
Apr 7 '09 #9

Sign in to post your reply or Sign up for a free account.

Similar topics

3
by: Dave | last post by:
I have a Solution with two projects. I am trying to reference a class in project2 from project1. When I right click on the project1 references (in Solutions explorer)and attempt to add a...
15
by: Guenther Sohler | last post by:
This is probably very easy to answer but for me its new. Yesterday I realized the need to be able to define a class within another one. So I have written some test code and its almost syntax error...
2
by: uvts_cvs | last post by:
template <class T> class foo { public: template <class Tin> T bar (Tin) {return T();} };
4
by: Stephen Corey | last post by:
I've got 2 classes in 2 seperate header files, but within the same namespace. If I use a line like: // This code is inside Class2's header file Class1 *newitem = new Class1(param1, param2); ...
2
by: Craig Buchanan | last post by:
If I declare a class within another class like: Class ParentClass ... Class ChildClass ... End Class End Class How do I reference a property in the ParentClass in the ChildClass? If the
2
by: Billy | last post by:
In .Net 2, when I have created a strongly typed dataset of a SQL table and then 'viewed' the code from the RHM menu. I am taken to the new partial class; as expected, but why do I have a partial...
2
by: Gman | last post by:
Hi, I have created a usercontrol, a grid control essentially. Within it I have a class: clsGridRecord. I have coded the events such that when a user clicks on the grid, say, the events occur on...
3
by: Nick Valeontis | last post by:
Hi to all! I am writing an implentation of the a-star algorithm in c#. My message is going to be a little bit long, but this is in order to be as specific as possible. My question has nothing to...
7
nathj
by: nathj | last post by:
Hi, I have a data abstraction class that holds all the functions for query the database. I now have a second class that holds all the functions for writing specific data to the database. ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.