473,573 Members | 2,842 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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

88 New Member
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 22852
Markus
6,050 Recognized Expert Expert
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 New Member
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 Recognized Expert Moderator Expert
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 New Member
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 Recognized Expert Moderator Expert
[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 New Member
Dormilich, thanks for that clarification.

I have implemented what you desribed and its working fine.

Thank you.
Apr 7 '09 #7
Dormilich
8,658 Recognized Expert Moderator Expert
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 Recognized Expert Moderator Expert
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
2136
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 reference, I get the add reference window, I click on Project tab and browse to my solution/project folder and then to the project2.exe. However, I...
15
17565
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 free. My first goal is to count the Outer classes with a global variable, which works fine But then I want to count the Inner classes within...
2
274
by: uvts_cvs | last post by:
template <class T> class foo { public: template <class Tin> T bar (Tin) {return T();} };
4
2712
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); I get "syntax error: identifier" and "undeclared identifier". Since they're in the same namespace, and even in the same project, do I need
2
7404
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
1260
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 class within a partial? plus if I was to inherit an interface then what partial class should I place the interface on, the outer partial class or the...
2
1689
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 the parent form. This is fine. The problem occurs when I want to raise an event for a user clicking on one of the clsRecords which are on the...
3
2272
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 do with the algorithm. It is related to OOP in c#. I have created a class named astar.cs. An instance of the class among other, contains a...
7
2137
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. The class definitions are all in the same php file and I need to use the first class within the second. On the page where the functions of the...
0
7784
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7704
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
8031
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
1
7795
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
8073
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
1
5600
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
5294
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3734
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
1044
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

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.