I have an issue accessing top level variables from sub-level class.
Here's an example...
Application.php:
class Application {
var $config;
var $db;
function __construct() {
include_once('Configuration.php');
include_once('Database.php');
$this->config = new Configuration;
$this->db = new Database;
}
}
Configuration.php:
class Configuration {
var $dbhost = 'localhost';
}
Database.php:
class Database {
function __construct() {
echo parent::config->dbhost;
}
}
It is clear to me that usage of parent is wrong here as the subclass does not extend the parent class, but how do I access it?
Thank you.
You should create a Base class that in its construct creates a $db link. Then let all classes that require database access extend that class. Your nomenclature here with "parent class" is incorrect.
class Base {
private $db; // Make it read-only
function __construct() {
$this->db = DB::connect(); // It's a good practice making this method static
}
function __get($property) {
return $this->$property;
}
}
class Application {
public $config;
function __construct() {
parent::__construct();
require_once 'Configuration.php';
require_once 'Database.php';
$this->config = new Configuration();
}
function random_function() {
$this->db(....) // Has full access to the $db link
}
}
The parent notation is used to access the parent of the object in the object hierarchy. What you are doing here is trying to get at the caller, not the parent
The way that you would do this is to pass in an instance of your configuration to the database object.
class Database {
protected $config;
public function __construct(Configuration $config){
$this->config = $config;
}
public function connect(){
//use properties like $this->config->username to establish your connection.
}
}
The parent notation is used when you extend a class and make a child class to call methods on the parent .
class MySuperCoolDatabase extends Database {
protected $is_awesome;
public function __construct(Configuration $config){
// do all the normal database config stuff
parent::__construct($config);
// make it awesome
$this->is_awesome = true;
}
}
This defines a child class, which is a type definition that serves the same role as the base class with a slightly different implementation. Instances of this can still be said to be a Database.... just a different kinds of database.
Well, although I think that Orangepills answer is better. If you dont want to use it and since all variables are public, you could simply pass the variable like this:
class Application {
var $config;
var $db;
function __construct() {
include_once('Configuration.php');
include_once('Database.php');
$this->config = new Configuration;
$this->db = new Database($this->config->dbhost);
}
}
class Configuration {
var $dbhost = 'localhost';
}
class Database {
function __construct($dbhost) {
echo $dbhost;
}
}
Related
There are already many threads about this kind of problem, but for some reason i can't get it to work.
In TestClass::test(), $db is NULL.
The $db value is set in App construct and I'm trying to recover that value from an extended class function. (so i don't need to set $db everytime everywhere).
Some help would be greatly appreciated, thanks.
File : index.php
<?php
include('classes/App.class.php');
$oApp = new App();
echo TestClass::test();
?>
File : App.class.php
<?php
class App {
protected $db;
public function __construct () {
include_once("CAutoLoader.class.php");
$oCAutoLoader = new CAutoLoader();
$this->db = "someValue";
}
}
?>
File : TestClass.class.php
<?php
class TestClass extends App
{
function __construct () {
}
public static function test () {
return $db;
}
}
?>
File : CAutoLoader.class.php
<?php
class CAutoLoader {
CONST CLASS_EXTENSION = '.class.php';
public function __construct () {
spl_autoload_register(array($this, 'loader'));
}
private function loader ($className) {
include $className . self::CLASS_EXTENSION;
}
}
?>
You forgot a this in your TestClass and a static method cannot access non-static properties. Remove the static keyword and return the right value.
public function test() {
return $this->db;
}
Edit:
If you meant to retrieve the instance of the db via a static method you must declare the variable as static.
class App {
protected static $db = 'hey';
...
}
class TestCase extends App {
public static function test() {
return parent::$db;
}
}
echo TestCase::test(); // returns hey
Here is sample code:
namespace myApp
class app
{
private $pdo = null;
public function __construct() {
$this->user=new User();
$this->user->getPDO();
}
}
class User
{
public function getPDO() {
//get PDO from app class
}
}
How from User class get $pdo from app class??
Can't use extends because of construct in app class.
I don't want to declare independent classes (app and User) and than use global to communicate with each other.
EDIT:
is this solution ok?
namespace myApp
class app
{
public $pdo = null;
public function __construct() {
$this->user=new User($this);
$this->user->getPDO();
}
}
class User
{
private $app=null;
public function __construct($app) {
$this->app=$app;
}
public function getPDO() {
return $this->app->pdo;
}
}
This sounds like a good candidate for dependency injection.
You can declare the constructor for your Userclass for example like
__constuct($pdo) {
$this->pdo = $pdo;
}
And then create User like
$this->user = new User($this->pdo)
An added advantage of this is that when you want to test your code you can easily mock pdo and test user without doing actual database actions.
You have to declare 2 functions in your app class like this:
Then you have acces through this functions to the pdo variable
public function setPDO($pdo) {
$this->pdo = $pdo;
}
public function getPDO() {
return $this->pdo;
}
I'm trying to learn how to properly code PHP OOP.
This is where I'm running into issues.
I created several classes that extend main Application class and I want to make things work properly.
I have main file that's index.php that looks like this:
include_once('classes/Application.php');
include_once('classes/Configuration.php');
include_once('classes/Database.php');
$app = new Application;
$config = new Configuration;
$db = new Database;
var_dump($app->db_connected);
var_dump($db->db_connected);
$db->connect($config->dbhost, $config->dbuser, $config->dbpass, $config->dbname);
var_dump($app->db_connected);
var_dump($db->db_connected);
The output is:
1. bool(false)
2. bool(false)
3. bool(false)
4. bool(true)
My main application file looks like this:
class Application {
public $db_connected = false;
}
And my Database class looks like this:
class Database extends Application {
function connect($dbhost, $dbuser, $dbpass, $dbname) {
if(!$this->db_connected) {
mysql_connect($dbhost, $dbuser, $dbpass) or die(mysql_error());
mysql_select_db($dbname) or die(mysql_error());
$this->db_connected = true;
}
}
}
So the question is, why would line #3 of the output of index.php display false? The db_connected property has been overridden in Database class and set to TRUE, but it still returns false.
Although when accessed directly from Database class instance it shows TRUE correctly. What's the deal here?
Also when does the class EXTEND command occurs? Whenever parent class' instance is created or I have to manually create instance of the child class?
It seems you are reaching for the concept of of a static variable all instances of a class share the same static variable so using the new twice will not be an issue.
You can see the code on ideaone.
// your code goes here
class Application {
static $db_connected = false;
}
class Database extends Application {
function connect() {
if(!static::$db_connected) {
static::$db_connected = true;
}
}
}
$app = new Application;
$db = new Database;
var_dump(Application::$db_connected);
var_dump(Database::$db_connected);
$db->connect();
var_dump(Application::$db_connected);
var_dump(Database::$db_connected);
Your comment make me think you are looking for a better pattern all together. I would like to throw out some key principles namely OCP and LSP SOLID.
In this case you would avoid having Application being an instance of Database but instead use dependency injection. Here is the refactored code.
class Database {
private $db_connect = false;
public function connect () {
if(!$this->db_connect) { /* do connection */ }
}
}
class Application {
private $db;
public function setDatabse(Database $db) {
$this->db = $db;
}
public function getDatabase() {
return $this->db;
}
}
$db = new Database;
$app = new Application;
$app->setDatabase($db);
$app->getDatabase()->connect();
This line is your hint
Although when accessed directly from Database class instance it shows TRUE correctly. What's the deal here?
You have 2 instances. Above you are checking $db instance which you connected with, and then you print from $app which was never connected. They are separate entities, one is connected one is not.
Extend occurs as soon as the file is loaded, read by the php interpreter, this happens regardless of ever using the class.
Extend is called from the child and inherits everything form the class it extends. So if you call a child method in the parent, well you are doing it backwards. It goes one way, Prent -> Child.
I would use Dependance injection for the database, then you can reuse it's code.
Like this:
//parent class
class Application {
//holds a reference to the Database class
protected static $db_conn = false;
public function __construct($db){
self::$db_conn = $db;
}
}
//child class of Application
class Application2 extends Application {
public function getSomething($id){
return self::$db_conn->getbyId($id) ;
}
}
//separate utility class
class Database{
static $conn;
public function __construct( $dbhost, $dbname, $dbuser, $dbpass, $dbname) {
static::$conn = mysqli_connect($dbhost, $dbuser,$dbpass,$dbname);
}
public function getbyId( $id ){
..code to get stuff by id using $conn - previous connection ...
return $result;
}
}
$db = new Database("myhost", "myuser", "mypassw", "mybd");
$app = new Application2( $db );
$app->getSomething(1);
//create another app with the same database connection, this is the value of injecting it.
$second_app = new Application2( $db );
See you can reuse database over and over, you can replace it without changing the code in Application as long as the calls for the functions of the Database class don't change. Each thing is responsible for it's own business.
This is called separation of concerns.
Inheritance is good, when it's needed. You might have an basic application for free users of you're services and then extend that with a premium application for paid members. Sense they paid they get all the free functionality, but also the premium stuff to.
In my example above the database is something they both need, as well as other things will probably use this. Such as a login system may need a database connection, payment system might, a shopping cart might. These are all separate objects, they don't / nor should they extend off of one Master Class, that's a bad idea. Keep them separate.
STATIC
I seen mention of the :: static object operator. My example is a bit flawed when using the static property protected static $db_conn = false;
$app = new Application2( $db );
$second_app = new Application2( $db ); //assigning db 2x is not needed.
The reason for :: and the -> normal way. Is that static :: is shared across all instance of a class, and -> is just this instance of the class. I had assigned the $db class to a static variable 2 times a better way would have been like this.
//parent class
class Application {
protected static $db_conn = false;
//separate method then construct.
public function connect($db){
self::$db_conn = $db;
}
}
//we'll keep the rest of the code the same here.
$db = new Database();
$app = new Application2();
$app->connect( $db );
$second_app = new Application2();
$second_app->getSomething(1);
Now in this example $second_app never ran it's connect method. But because the first $app did and because the static for the database variable protected static $db_conn. Now all classes that have extended the Application class have a database connection. This is what static does. It's value is shared across all instance of the class. So when you see :: think all class instance and when you see -> think only this class instance. It's actually one thing I love about php, makes it so much easier to keep track of then in some other languages.
Not to confuse you but the other use of the :: is not actually needing an instance at all. Assume you have a Config class like this.
class Config{
static $db = 'hello';
static $items = array('one' => 'item 1' );
private __construct(){} // no construction allowed
static function getItem( $which ){
return self::$items[$which];
}
}
Now without ever creating an instance of the class by calling new Config() , you can simply.
echo Config::$db;
// prints hello
echo Config::getItem('one');
// prints 'item 1'
This is quite use full for config type classes. Where they are an empty shell just used to store data in and you don't need an object for them, essentially a way to keep things organized. So tying this in to the previous examples
$db = new Database(Config::$myhost, Config::$myuser, Config::$mypassw, Config::$mybd);
In your case best OOP practice is to use Mediator pattern. Concrete Mediator will be Application class:
class ApplicationBase {
private $db;
private $cfg;
public function setDb(Database $db) {
$this->db = $db; return $this;
}
public function setConfig(Config $cfg) {
$this->cfg = $cfg; return $this;
}
}
class Application extends ApplicationBase {
public function getDsn() {
return $this->cfg->getDsn();
}
public function getDbUser() {
return $this->cfg->getDbUser();
}
public function getDbPass() {
return $this->cfg->getDbPass();
}
public function getConnection() {
return $this->db->getConnection();
}
}
class AppComponent {
protected $app;
public function __construct(Application $app) {
$this->app = $app;
}
}
class Config extends AppComponent {
private $dsn;
private $dbuser;
private $dbpass;
// ... getters and setters
}
class Database extends AppComponent {
private $connection;
private function connect() {
$this->connection = new PDO(
$this->app->getDsn(),
$this->app->getUser(),
$this->app->getPass()
);
}
public function getConnection() {
if (null === $this->connection) $this->connect();
return $this->connection;
}
}
class Model extends AppComponent {
protected $table;
// Model stuff here
}
class Content extends Model {
public function getNews() {
$db = $this->app->getConnection();
return $db->query("SELECT * FROM $this->table LIMIT 5")->fetchAll();
}
}
Such architecture will be enough for simple, clean-looking applications and classes will be ready for easy unit-testing:
$app = new Application();
$cfg = new Config($app);
$db = new Database($app);
$app->setDb($db)->setConfig($cfg);
$content = new Content($app);
$news = $content->getNews();
I am building an API in PHP and I have a question. I'm using classes, and some of these classes need to access my database. However, I don't want to define variables for the database in every single class in order to open it, or have to send my mysqli object as a parameter of every single class constructor.
What would be the best way to go about this? Do I define a global variable of some kind?
A classic solution would be as follows
Create an instance of dbatabase handler class, either raw mysqli (worse) or better abstraction class (way better)
In the constructor of your application class take this db class instance as a parameter and assign it to a local variable
Use this variable with your class.
A quick example:
class Foo()
{
protected $db;
function __construct($db);
{
$this->db = $db;
}
function getBar($id)
{
return $this->db->getOne("SELECT * FROM bar WHERE id=?i", $id);
}
}
$db = new safeMysql();
$foo = new Foo($db);
$bar = $foo->getBar($_GET['id']);
How about using a static classes?
class mysqli_wrapper {
private static $db = null;
public static function open() {
GLOBAL $opts; // this can be global or setup in other ways
if (!self::$db) {
self::close();
self::$db = null;
}
self::$db = #mysqli_connect('p:'.$opts['hn'], $opts['un'], $opts['pw'], $opts['db']);
return self::$db;
}
public static function query($qry) {
return mysqli_query ( self::$db, $qry );
}
public static function affected_rows() { return #mysqli_affected_rows(self::$db); }
public static function error() { return #mysqli_error(self::$db); }
public static function close() { #mysqli_close(self::$db); }
} // end mysqli_wrapper
mysqli_wrapper::open(); // Here's how to call it
In a system I maintain my app needs to access its own MySQL db, as well as remote Oracle and SQL Server databases, and I use a trait for it. Here's a simplification of my code, just using MySQL:
dbaccess.php
trait DatabaseAccess {
protected $db;
private $host = 'host', $dbName = 'db', $username = 'username', $password = 'pword';
public function connectToMysql() {
$this->db= new mysqli(......);
}
}
then in myclass.php
require 'dbaccess.php';
class MyClass {
use DatabaseAccess;
//class code.....
}
All elements of DatabaseAccess will be available as if you hand-typed them in MyClass.
Note: if you're using PHP < 5.4, then this solution won't be possible.
I am trying to make a script in which different classes (e.g. Database, Utilities, Config) are all used to form one central Main class. I have tried extending a chain of them:
Main -> Utilities -> Database -> Configuration
But how can I set the different parts so that they can be called like this:
<?php
$this->db->select("WAFFLES");
echo($this->config->app_path);
?>
You could create a global class that does you basic initializing
class Base {
$var1, var2;
public function __construct() {
$this->var1 = new DB();
$this->var2 = new Config();
....
}
}
Then your classes can extend the base class and have access to the data
class Foo extends Base {
public function bar() {
$this->var1->someOpertaion();
}
}
You need to declare each new object as variable in your Main Class like:
class Main{
private $db = NULL;
private $config = NULL;
$this->db = new Database;
$this->config = new Config;
}
etc.
While i'm not a professional coder i'll considering a better approach than this. This kind of object-handling can cause a bloated main class and in the worst case you may face some performance issues.
1) use __autoload or spl_autoload_register to load classes
2) use magic methods, to call function when getting unknown property. Following examples demonstrates how to use __get and dynamicaly initialize object only when you use them.
//use __autoload to load db and config class when they are called.
class db{
function lol(){
echo 'Hello from db->lol() <br />';
}
}
class config{
function lol(){
echo 'Hello from config->lol() <br />';
}
}
//Manager class to use with classes where you want to access other object trough $this
class Manager{
private $_instances=array();
function __get($name){
//if instance does not exists, create one
if (!isset($this->_instances[$name])){
$this->_instances[$name]=new $name();
}
//return instance
return $this->_instances[$name];
}
}
class Some extends Manager{
function f1(){
$this->db->lol();
$this->config->lol();
}
}
$some=new Some();
$some->f1(); //echoes 'Hello from db->lol()' and 'Hello from config->lol()'
But for accessing global class instances I prefer using following method:
Use singleton pattern to access global class trough GloballClass::i() and if global class is not defined use autoload to load that class.
class db extends mysqli{
private static $_i;
//Access to singleton instance
public static function i() {
return (self::$_i instanceof self)?self::$_i:self::$_i = new self();
}
//class functions
function q($q){
echo 'Hello from db->q()';
}
}
class config{
private static $_i;
//Access to singleton instance
public static function i() {
return (self::$_i instanceof self)?self::$_i:self::$_i = new self();
}
//class functions
function somefunction(){
echo 'Hello from config->somefunction()';
}
}
db::i()->q('SELECT * FROM users');
config::i()->somefunction();
Following is solution inspired by Gordons comment:
It uses GlobalClassFactory class to define only one instance of global classes.
class db{
function lol(){
echo 'Hello from db->lol() <br />';
}
}
class config{
function lol(){
echo 'Hello from config->lol() <br />';
}
}
class GlobalClassFactory{
private static $_classes=array();
public static function getInstance($name){
if (!isset(self::$_classes[$name])){
self::$_classes[$name]=new $name();
}
return self::$_classes[$name];
}
}
class Base{
function __get($name){
return GlobalClassFactory::getInstance($name);
}
}
class Some extends Base{
function f1(){
$this->db->lol();
$this->config->lol();
}
}
$some=new Some();
$some->f1();
Here is the sample prototype:
include 'db.php'; // include db class
include 'config.php'; // include config class
class main{
public $db = NULL;
public $config = NULL;
function __construct() {
$this->db = new db;
$this->config = new config;
}
}
Creating a composite object with instances of everything that might be needed during code execution up front is a complete waste of resources. You want to create instances only when needed. One way to achieve this would be to add a magic __get method to the class:
public function __get($name) {
// if self::$instances (or main) contains instance of $name, return instance
// else if class_exists $name, create, store and return instance
// else throw exception
}
But even then, chances are you are creating a God Object and magic methods are somewhat slower than regular accessors. If you need to create instances this way, have a look at the Symfony Dependency Injection Container or implement a Registry.