why I can't do like this?
<?php
class core {
public static $db;
function __construct() {
$this->db = new mysql('host', 'user', 'pw', 'db');
}
}
class stat extends core {
public static function log() {
core::$db->query("insert into mytable values(now())");
}
}
// do something
stat::log();
?>
By the looks of your code, because you don't assign anything into $db. The constructor is only called when you create an instance of the class, not with statics.
Also, why is your code even extending core? You don't need to extend it to use static methods/variables. Perhaps it would make more sense to actually make it an instance property, and use a new instance instead of static?
The core::__construct() method is only called when you call new core or new stat, invoking the creation of an object. You go straight to stat::log(), so core::$db has never been initialized.
Related
I have two classes ('database' and 'app'). 'app' extends 'database';
both classes have the namespace 'cms'.
The problem is i want to call the method close() of a mysqli object that is stored inside an attribute of class 'database'. When i try to call that method, I get the error :
Call to undefined method cms\database::close()
I know that in order to call a function that belongs to PHP's base namespace when currently using a diffrent namespace you can add a "\" in front of that function. But how could you do something similar with the method of a mysqli_object (like $this->connection->close())? Is my whole approach wrong (if yes what should i do instead)?
I tried something like this in the destructor
call_user_method("close", $this->connection);
but i get an error which says that "close" can't be called.
My code looks as follows:
index.php
<?php
use cms\app;
require_once "class.database.php";
require_once "class.app.php";
$app = new app();
?>
class.app.php
<?php
namespace cms;
use cms\database;
class app extends database {
public $connection;
public function __construct(){
$this->connection = new database();
}
}
?>
class.database.php
<?php
namespace cms;
class database {
public $connectionData = array (
"server" => "localhost",
"user" => "root",
"password" => ""
);
public $connection;
public function __construct() {
$this->connection = mysqli_connect(
$this->connectionData["server"],
$this->connectionData["user"],
$this->connectionData["password"]
);
}
public function __destruct() {
call_user_method("close", $this->connection);
}
}
?>
Sorry for the long post and thanks in advance for any help.
Your problem is not namespaces. In cms\database, you define $this->connection as a mysqli object. The destructor accordingly wants to call $this->connection->close() on it. Straight forward and simple.
cms\app now overrides this and defines $this->connection as a cms\database object. The inherited destructor still wants to call $this->connection->close() on it. Well, cms\database doesn't have a method close, just as the error says.
Your issues are:
You're overriding __construct which is defining $this->connection as something it shouldn't be. Simply do not override __construct and/or at the very least call parent::__construct and don't redefine $this->connection to a different object.
Your cms\app is extending cms\database. This doesn't make a whole lot of sense on the face of it. Is your app a database? Could you replace any instance of database with an instance of app? Does that logically make sense? Probably not. It does not look like app should extend database at all. If you get rid of that weird relationship, your problem will be solved as well. Then look into Dependency Injection.
I'm building a PHP OOP MVC Framework for personal use.
I'd like to know if there's a way or the correct implementation of the following:
Being able to call a method from a "subclass" (not extended) to another "subclass". I mean...
I have a class that creates new objects for each subclass instead of using inheritance. Let's call it MainClass, and it has 3 "SubClasses" like this
class MainClass {
public $db;
public $forms;
public $pagination;
function __construct() {
$this->db = new class_db();
$this->forms = new class_forms();
$this->utils = new class_utils();
}
}
And the initialization which is
$MainClass = new MainClass();
I can do for example
$MainClass->utils->show_text("Hello World");
And works fine.
What I'd like to do is... within the $MainClass->utils->test() (Another test method), is to be able to access $MainClass->db without using global or $GLOBALS.
Is there any alternative way of achieving this? To be able to access $MainClass methods and submethods within another submethod (access db from utils and from the main page where MainClass is initialized)? How would it be? I want to be able to access al the submethods, like utils being able to access db and forms method. as well as the pages that are outside MainClass.
Thank you
If utils has to use db, you either have to pass the MainClass instance to utils, so it can call $this->myRefToMain->db, or pass the instance of db itself, so utils can call $this->db. Either way, it cannot (reasonably) crawl up the call stack to find the object that called it.
Object if your class class_utils can exists without MainClass. And its method test() should access some object db of class class_db. This means class_utils depends on class_db and you should inject object of class_db in constructor, for example:
class MainClass {
public $db;
public $forms;
public $pagination;
function __construct() {
$this->db = new class_db();
$this->forms = new class_forms();
$this->utils = new class_utils($this->db);
}
}
Let's say I'm writing a PHP (>= 5.0) class that's meant to be a singleton. All of the docs I've read say to make the class constructor private so the class can't be directly instantiated.
So if I have something like this:
class SillyDB
{
private function __construct()
{
}
public static function getConnection()
{
}
}
Are there any cases where __construct() is called other than if I'm doing a
new SillyDB()
call inside the class itself?
And why am I allowed to instantiate SillyDB from inside itself at all?
A private constructor makes sure you cannot instanciate this class outside of itself.
So calling
$obj = new SillyDB();
would result in an error.
This technique is usually used when creating singleton classes.
This stone old comment in the manual describes it pretty well: http://www.php.net/manual/de/language.oop5.decon.php#80314
You have a static method inside the class that manages a single instance of the class which can be retreived through the method.
Calling the static function within that class may run the construct from within the class.
class SillyDB
{
private function __construct()
{
$db->connect();
}
public static function getConnection()
{
self::__construct();
}
}
Running
SillyDB::getConnection()
will run the __construct() method and connect you to the db
Are there any cases where __construct() is called other than if I'm
doing a new SillyDB() call inside the class itself?
No.
And why am I allowed to instantiate SillyDB from inside itself at all?
Why would you not be allowed to?
The better question would be what use is it for a constructor that can only be called from inside its own class?. That is useful when you want to ensure total control of how instances are created, for example when you implement a singleton.
__construct() would only be called if you called it from within a static method for the class containing the private constructor. So for your Singleton, you might have a method like so:
class DBConnection
{
private static $Connection = null;
public static function getConnection()
{
if(!isset(DBConnection::$Connection))
{
DBConnection::$Connection = new DBConnection();
}
return DBConnection::$Connection;
}
private function __construct()
{
}
}
$dbConnection = DBConnection::getConnection();
The reason you are able/would want to instantiate the class from within itself is so that you can check to make sure that only one instance exists at any given time. This is the whole point of a Singleton, after all. Using a Singleton for a database connection ensures that your application is not making a ton of DB connections at a time.
You are able to call it because scope is checked based on class rather than instance (i.e. an object is able to access the private and protected methods/properties of another instance of the same class without issue)
So I have a config.php file, wich is included on top of every page on the site before the tag. This file uses __autoload() to get all the php classes I use. Then, after autoloading them I assign the classes to variables like so...
$myclass = new Myclass();
$mysecondclass = new MySecondClass();
When I want to call $mysecondclass in $myclass, I get an undefined variable error. This is of course, because $mysecondclass was not defined before $myclass. How do I fix this where I can define all classes from any other class?
Thanks for any help:)
The best OOP approach would be to use a superObject with properties which are objects of other classes.
class Context{
var $myClass;
var $myOtherClass;
var $db;
//...
}
In your MyClass
class MyClass{
var $context;
public function __construct(&context){
$this->context = $context;
}
public function otherFunction(){
$this->context->myOtherClass->functionFromOtherClass();
}
}
You should be instantiating these classes using Factory method or any mechanism to manage objects.
To initialize MyClass you would implement something like this.
ObjectFactory::createObject('MyClass',$context);
$myclass is not Myclass it is an instance of Myclass (an object). Objects are not classes. If you want to use a new instance of MySecondClass inside of an instance of Myclass, just instantiate it in there.
Your question also deals with scope. You have created these two objects in the global scope. They are not automatically accessible within one another. If you have some object which you will have only one instance of and which you want to be global and accessible by others, you can import it into their scope with the global keyword. However, this is not usually the best way to go about it. Instead, you may want to look up the Singleton Pattern. It gives you a way to ensure that a particular class is only instantiated one time and gives you a way to access the object that has been created as a result of that instantiation.
The registry pattern is also an easy way to access "global" object anywhere in your code.
You can Take a look at Zend_Registry : http://framework.zend.com/manual/en/zend.registry.using.html
$myclass = new Myclass();
$mysecondclass = new MySecondClass();
Zend_Registry::set('mysecondclass', $mysecondclass);
$myclass->doSomething();
class Myclass
{
public function doSomething()
{
// use $mysecondclass via the registry
Zend_Registry::get('mysecondclass')->methodFromSecondClass();
}
}
class MySecondClass
{
public function methodFromSecondClass()
{
return true;
}
}
According to how your classes works, think about extending them... Extending MyClass to MySecondClass automatically gives access to parent properties / functions.
MyClass
class MyClass{
function myFunction(){
// code here
}
}
MySecondClass
class MySecondClass extends MyClass{
function __construct(){
$this->myFunction();
}
}
I've encountered an architectural issue with my application. I've rolled my own (very basic) MVC, and one of my models is a database object: class MySQLDatabase { }
There's a number of places in which I'd want to use my database object, without creating duplicate instances. Inside my controller, I have declared public $db; and within the __construct { } I have $this->db = new MySQLDatabase;
Question:
How do I use $db within my other classes--they're all instantiated within the controller's __construct { } as well... would I declare global $db at the top of all my classes that require database connectivity?
I'm used to global variables being declared in the global scope as regular variables, and then using the global keyword to reference the global scope... I'm not sure if that applies to variables declared within a class (my controller.)
I would stay away from using globals or the Singleton pattern (which is essentially a global anyway), and try and find some alternatives. Additionally you are talking about a database connection, by using the Singleton pattern you are saying that there will never be more than one database connection, whilst that is generally true in smaller applications, as they grow larger you won't be able to accomodate multiple connections.
Once you make something global then you lose the automatic contraints of where it can be used/modified. Using MVC a view shouldn't be used for anything other than to display data, by using a global/singleton it is up to the developer to not make use of the globals. Whereas with a different design they don't have that option.
You mentioned you've created your own MVC framework, so I imagine the classes you want to use it in are your models? Correct me if they are anywhere else.
If your models extend from a common base class then you could pass your database object to that class as a static variable which can be assigned to any new instances in the construct or using a factory method in the factory method.
This isn't to say that globals or singletons should be avoided at all costs, but definitely try consider the alternatives that could lead to a neater design.
Here's some reading on the Singleton pattern if you're interested:
Patterns I Hate #1: Singleton
Why Singletons are Evil
Singleton Considered Stupid
Use your singletons wisely
There are many more out there...
If I understand correctly you have a single controller that instantiates the database object and it also takes care of instantiating other classes. If so, you could implement some form of dependency injection either passing the db object in the constructor of the other classes or creating a setter method.
A good blog article on the subject:
http://www.potstuck.com/2009/01/08/php-dependency-injection/
I Think you going about this the wrong way, you should not be performaing quesries to the database from you controller.
this means that the below is invalid.
class ControllerIndex extends Controller
{
public function index()
{
$this->db->selectAll("table");
}
}
There should be a layer that separates your controller from your database interface, this is where a Model comes in.
You should have a models folder that contain classes for actions taken such as users,posts,logging etc.
class Users_Model extends Model
{
public function getUser($id)
{
}
}
The model class should be part of your system core, and should extend your Database Class, this way within your main controller you should be loading the models via the ModelLoader class.
for example:
class ModelLoader
{
private $models = array();
public function __get($model)
{
//load (/application/models/?.php) and initiate it here
//Storing it in models array above
}
}
Then in your main controller:
class Controller
{
private $model;
public function __construct()
{
$this->model = new ModelLoader;
}
}
this way your bringing your loader into scope for the child controller:
class Controller_index extends Controller
{
public function index()
{
$user = $this->model->users->getUser(22);
}
}
Hope this helps!
I think what you need here is a singleton for you Database object :)
See here for more details : http://en.wikipedia.org/wiki/Singleton_pattern
Edit with sample singleton for php :
<?php
class UniqueObject {
private $_uniq = null;
//private cause you don't want to instanciate the classic way
private function __construct() {
//...
}
//check if unique object exists or not, then return it
public static function uniq() {
if(!self::$_uniq)
self::$_uniq = new UniqueObject();
return self::$_uniq;
}
}
//call your unique object whenever you need it
UniqueObject::uniq();
?>
(it's late, i hope i didn't do any mistake :))
Don't use singletons. It's much better to explicitly pass around data. For example:
abstract class Controller {
private static $conn; // could be an array for multiple connections
final protected function getDBConnection() {
if (!$this->conn) {
$this->conn = new DBConnection();
}
return $this->conn;
}
abstract public function process(Request $r);
}
class HomePageController extends Controller {
public function process(Request $r) {
$results = $this->getDBConnection()->query('SELECT stuff FROM foo;');
// do stuff with $results
}
}
You could also have an explicit model object you pass around, e.g. the one that represents the user, but that may be overkill for your project.
You'll need to use a singleton pattern. They give examples in the php docs
<?php
class Example
{
// Hold an instance of the class
private static $instance;
// A private constructor; prevents direct creation of object
private function __construct()
{
echo 'I am constructed';
}
// The singleton method
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
// Example method
public function bark()
{
echo 'Woof!';
}
// Prevent users to clone the instance
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
}
?>
http://php.net/manual/en/language.oop5.patterns.php