How to set value for public variable when this in another context and self wants only static props, which seems not be accessible after instantiation. There is a little extends for mysqli connection:
class db extends mysqli {
...
public static $bar;
private function __construct() {
self::$bar = "test";
...
}
db::setOptions($db_options);
$link = db::getInstance();
echo $link->bar;
Notice: Undefined property: db::$bar in ... blah-blah-blah
Is there a right way to do it? Thanks in advance.
As stated in the comments designating this as a static property makes the property belong to the class as opposed to an instance of an object of the class. To access class properties you have to use classname::$propertyName to access the property.
What you probably mean to do is:
class db extends mysqli {
protected static $instance;
public $bar;
private function __construct() {
$this->bar = "test";
}
public static function getInstance(){
if (!isset(static::$instance)){
static::$instance = new static();
}
return static::$instance;
}
}
$link = db::getInstance();
echo $link->bar;
UPDATE
Looking at the problem you are having I think you are just trying to provided global access to a shared db object that you can extend. If that is the case you may get better mileage from providing a wrapper for a mysqli instance instead of extending it. A simple way to do this is to create a wrapper object that proxies all undefined property access to an internally stored object.
class db {
protected $db;
public $bar;
protected static $instance;
protected function __construct(){
$this->db = new mysqli (....);
$this->bar = "something";
}
public static function getInstance(){
if(!isset(static::$instance)){
static::$instance = new static();
}
return static::$instance();
}
// magic accessor proxy
public function __get($property){
return $this->db->$property;
}
// magic mutator proxy
public function __set($property, $value){
$this->db->$property = $value;
}
// magic call function
public function __call($method, $args){
return call_user_func_array(array($this->db, $method), $args);
}
public function __callStatic($method, $args){
return call_user_func_array(array(static::getInstance(), $method), $args);
}
}
Related
I have an Connection class which connects to a specific "Service". You call the specific Service such as mysqli or PDO when instantiating the class.
class Connection
{
private $service;
private $state = null;
public function __construct(Service $service) {
$this->service = $service;
}
public function initialize() {
....
}
public function destruct() {
....
}
//Maybe some getters and setters
}
In the Service class there is an getObject() method, this contains the object which has to be instantiated to make a connection to a Database or something else.
There is also an getInstance() method. This is used for returning the object in the getObject method if it isnt already instantiated.
abstract class Service
{
public static function getInstance() {
$instance = null;
if ($instance == null) {
$instance = self::getObject();
}
return $instance;
}
/**
* #return object Returns the object where the service should start from.
*/
public abstract function getObject();
}
Here is an example of an Service class.
class MySQLService extends Service
{
public function getObject() {
return new mysqli('127.0.0.1', 'root', '', 'db');
}
}
Problem
When using this code like this:
$connection = new Connection(MySQLService::getInstance());
$connection->initialize();
It comes with this error:
Fatal error: Cannot call abstract method Service::getObject() in
C:\Users.\Documents...\Service.php on line 18
Questions
How does it come that this error appears?
How can I solve this error?
How can I call a function from a class that extends the Service class?
In order to get this working you need to declare the getObject methods as the static methods they are.
In Service:
public abstract function getObject()
Should be:
public static function getObject() {}
(Sorry, you can't have a static abstract)
In MySQLService:
public function getObject() {
Should be:
public static function getObject() {
You can then direct the call to the right class by using the following:
public static function getInstance() {
static $instance = null;
if ($instance == null) {
$instance = static::getObject();
}
return $instance;
}
Note - you missed the static keyword from the instance variable too.
So, in PHP, I know that static classes exist in the Global namespace, and thus cause overhead when having to call them.
But what happens when you assign a local class variable, or just a local variable, to that static class? Is the overhead of the Global reference removed?
In my specific case, I'm using a static singleton.
class Registry {
public static $user;
public static $DB;
public static $config;
public static $user_data;
private static $initialized = FALSE;
public static function init($config) {
if (!registry::$initialized) {
registry::$config = $config;
registry::$DB = new db($config['mysql']);
registry::$user = new user();
registry::$initialized = TRUE;
} else {
throw new Exception('Registry has already been initialized.');
}
}
}
Now, to make the question clearer, would it be beneficial to map the Registry in another class to a class variable/local variable for successive function calls?
class SomethingSomethingDarkSide {
private $registry;
private $db;
private $config;
public function __construct() {
$this->registry = Registry;
$this->db = Registry::$db;
$this->config = Registry::$config;
}
}
Since the static members are now assigned to a class variable after it's been initialized, would calling successive methods that utilize those class variables remove the overhead of the Global namespace that persist with static members?
EDIT: Please remove the idea of Singleton in this case. The question is more about whether we have to look up Registry each time after its been referenced to a variable.
IE:
$registry = Registry;
$registry::doSomething();
$registry::doSomething2();
$registry::doSomething3();
vs.
Registry::doSomething();
Registry::doSomething2();
Registry::doSomething3();
OR:
class Test {
public static function sayHi() {
echo 'Hi';
}
}
$test = Test;
echo $test::sayHi(); // This being done multiple times versus
echo Test::sayHi(); // That being done multiple times
I think your initial problem is that your Singleton implementation is not correct. Look at this code instead:
class Registry {
private static $instance = null;
private $user;
private $DB;
private $config;
private $user_data;
public static function getInstance($config) {
if (self::$instance === null)
{
self::$instance = new self($config);
}
return self::$instance;
}
private function __construct($config) {
$this->$config = $config;
$this->$DB = new db($config['mysql']);
$this->$user = new user();
}
public function doThing() {
}
}
$registry = Registry::getInstance($config);
$registry->doThing();
Since the constructor is private, the only way to get a new instance of Registry class is to use the public static method getInstance.
From then, you have a $registry variable which points to an instance of the Registry class (if it's not what you want then I don't understand why you are using the Singleton pattern...)
I think that's pretty close to want you want:
$registry = Registry;
$registry->doSomething();
$registry->doSomething2();
$registry->doSomething3();
class singleton:
class Singleton
{
private static $_myself;
private function __construct(){}
public static function getInstance()
{
if(!isset(self::$_myself))
{
$obj = __CLASS__;
self::$_myself = new $obj;
}
return self::$_myself;
}
}
my class:
class MyApp extends Singleton
{
public function show()
{
echo 'show';
}
}
MyApp::getInstance()->show();
but not working, this error:
Call to undefined method Singleton::show()
somebody can help me?
Because you're returning a Singleton class (as you can see by your error), but should be returning a MyApp class. You can do this by using the late static binding method get_called_class() introduced in PHP 5.3:
public static function getInstance()
{
if(!isset(self::$_myself))
{
//__CLASS__ = Singleton | get_called_class() = MyApp
$obj = get_called_class();
self::$_myself = new $obj;
}
return self::$_myself;
}
self returns the actual class instance (Singleton in this case), so there is no method show. But you could use static instead of self (Differences) and change $_myself from private to protected so it is accessible in child classes.
class Singleton
{
protected static $_myself;
private function __construct(){}
public static function getInstance()
{
if(!isset(static::$_myself))
{
static::$_myself = new static;
}
return static::$_myself;
}
}
The problem is in
$obj = __CLASS__;
self::$_myself = new $obj;
You create a new instance of the class Singleton, not of the class MyApp, so the method is not available.
Now h2ooooooo was faster with his answer than I edited, see his answer regarding what to put instead of __CLASS__.
I want to use a static method of an example class without instantiating class. This method uses a dependencie class and is instantiated with __construct method. How can this dependency class be instantiated. Example:
class user {
protected static $db;
public function __construct() {
self::$db = database::getInstance();
}
public static function get_user() {
$user = self::$db->query("sql");
return $user;
}
}
I know the solution with autoloader or I could just add self::$db = database::getInstance(); in every static method.
Could someone kindly show me better suggestions?
You can add a static setter and getter for the db object and throw an exception if someone tries to access the getter without calling the setter first:
class User
{
protected static $db;
public static function setDB($db)
{
self::$db = $db;
}
protected static function getDB()
{
if (!self::$db) {
throw new Exception('You must `setDB()` the db object before attempting to get it.');
}
return self::$db;
}
public static function getUser()
{
return self::getDB()->query('sql');
}
}
User::setDB(database::getInstance());
User::getUser();
From php manual:
[...] Static method calls are resolved at compile time.
When using an explicit class name the method is already identified completely and no
inheritance rules apply. If the call is done by self then self is translated to
the current class, that is the class the code belongs to.
Here also no inheritance rules apply [...]
..so im looking for a way to emulate the standard oop inheritance with static singleton.
Code explain better:
// Normal inheritance: my goal.
class Foo{
public function test(){
echo "Foo->test()\n";
}
}
class Bar extends Foo{
public function other_test()
{
echo "Bar->other_test()\n";
}
}
$obj = new Bar();
echo get_class($obj) . "\n";
$obj->test();
$obj->other_test();
/*
Output:
Bar
Foo->test()
Bar->other_test()
*/
// How i would love to do:
class Foo2{
public static function test2()
{
echo "Foo2::test2()\n";
}
// Singleton?
public static $_instance;
public static function get_instance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
}
class Bar2 extends Foo2{
public static function other_test2()
{
echo "Bar2::other_test2()\n";
}
}
$obj2 = Bar2::get_instance();
echo get_class($obj2) . "\n";
$obj2::test2();
$obj2::other_test2();
/*
Output:
Foo2
Foo2::test2()
Fatal error: Call to undefined method Foo2::other_test2()
*/
echo "\n-------\n";
// How im doing actually:
interface Foo3{
public static function get_instance();
}
class Bar3 implements Foo3{
// Singleton?
public static $_instance;
public static function get_instance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
public static function test3()
{
echo "Bar3::test3()\n";
}
public static function other_test3()
{
echo "Bar3::other_test3()\n";
}
}
$obj3 = Bar3::get_instance();
echo get_class($obj3) . "\n";
$obj3::test3();
$obj3::other_test3();
/*
Output:
Bar3
Foo3::test3()
Bar3::other_test3()
*/
The last 'way' force me to avoid the get_instance and static variables to be placed in the parent class, so I do not consider it as a best solution.. if for some reason my get_instance() function will change in the future, i dont want to edit all classes (inheritance! inheritance! we all want inheritance!)
So, is there a way or a best practices to solve this problem?
p.s: php5.3.2
The Singleton pattern in PHP is something like this:
class Singleton {
private static $instance = null;
// Constructor is private, so class cannot be instantiazed from outside
private function __construct() {
}
public static function getInstance() {
if (static::$instance === null) {
static::$instance = new Singleton();
}
return static::$instance;
}
public static function test() {
echo 'Singleton::test()';
}
public function __sleep() {
throw new Exception('Serialization is not alowed.');
}
public function __wakeup() {
throw new Exception('Serialization is not alowed.');
}
public function __clone() {
throw new Exception('Cloning is not alowed.');
}
}
For you is important that keyword static, then this:
class B extends Singleton {
public static function test2() {
echo 'B::test2()';
}
}
$b = B::getInstance();
B::test();
B::test2();
// Singleton::test()
// B::test()
Is this you looking for?