I have following setup.
index.php
require_once "common.php";
...
common.php
...
$obj = new MyClass;
require_once "config.php"
...
config.php
...
require_once "settings.php";
...
settings.php
$obj->dostuff = true;
...
When i open index.php i get: Strict Standards: Creating default object from empty value in settings.php on 3
If i put $obj->dostuff = true; inside config.php it does not produce error message.
Can someone explain why i get this error? I am not asking how to fix it just understand why.
EDIT: My bad i had 2 config.php classes for each part of site and i only changed something in one of them leaving old include order in another now it works fine after it all loads in correct order.
It looks a scope issue. In settings.php, the $obj is not accessible. PHP is creating new one from standard class, and giving you a warning. You can confirm it by putting
echo get_class($obj);
in Your settings.php, just after the line that is producing the error. If it echos "StdClass", then that is the case.
Are You sure the $obj is not created within a function/method ?
If $obj is meant to be a system wide globally accessible object, you can you use the singleton pattern to access from anywhere:
class MyClass
{
protected static $_instance;
static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
You can then create your methods in this class. To get the object itself simply call:
$obj = MyClass::getInstance();
Additionally, if you just want to call one of its methods but theres no need to return anything:
MyClass::getInstance()->objectMethod();
I find this to be a very efficient way to organize integral singleton based system wide operations.
In practice, my project uses this to get configuration from anywhere in the system:
class syConfig
{
protected static $_instance;
private $_config;
static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function load($xmlString)
{
$xml = simplexml_load_string($xmlString);
$this->_config = $xml;
}
public function getConfig()
{
return $this->_config;
}
}
Related
I have created a logger as a singleton for my PHP application with Zend framework.
Implementation is pretty straight-forward:
class Logger
{
protected static $_logger;
private function __construct()
{
// initialize logger
$writer = new Zend_Log_Writer_Stream(LOG_PATH);
$this->_logger = new Zend_Log($writer);
}
public static function getLogger()
{
if (null === self::$_logger)
{
self::$_logger = new self();
}
return self::$_logger;
}
public static function Log($message, $logType)
{
if ($logType <= LOG_MAX)
{
$logger = self::getLogger();
$logger->_logger->log($message, $logType);
}
}
}
To ad an entry to the log, I just call static method:
Logger::Log('message', Zend_Log::ERR);
Logger works as supposed to, but since I have upgraded my PHP version to 5.4.3 I get an error:
Strict standards: Accessing static property Logger::$_logger as non static in Z:\Software\PHP\EA Game\application\classes\Logger.php on line 28
Line 28 is in function __construct(): $this->_logger = new Zend_Log($writer);
I can always disable E_STRICT, but it is not a preferable option.
I would like to implement Singleton pattern without getting Strict standards warning.
I would be grateful if some could point me in the right direction to implementing Singleton pattern without getting String standards warning.
EDIT:
I used jValdrons advice and replaced $this->_logger to self::$_logger.
I still was getting strict standards warning and I changed Log function to be as follows:
public static function Log($message, $logType)
{
if ($logType <= LOG_MAX)
{
self::getLogger()->log($message, $logType);
}
}
But now I have another problem.
Code does not throw Strict standards warning, but it does not works as supposed to.
I have 2 separate loggers, 1 for application and 1 for crons.
Basically it's just the same code:
2 static variables:
protected static $_logger;
protected static $_cronLogger;
constructor initializes both of them:
private function __construct()
{
// initialize all loggers
$writer = new Zend_Log_Writer_Stream(LOG_PATH);
self::$_logger = new Zend_Log($writer);
$writerCron = new Zend_Log_Writer_Stream(CRON_LOG_PATH);
self::$_cronLogger = new Zend_Log($writerCron);
}
and 2 methods GetCronLogger() and LogCron():
public static function getCronLogger()
{
if (null === self::$_cronLogger)
{
self::$_cronLogger = new self();
}
return self::$_cronLogger;
}
public static function LogCron($message, $logType)
{
if ($logType <= CRON_LOG_MAX)
{
self::getCronLogger()->log($message, $logType);
}
}
But now self::getCronLogger()->log($message, $logType); calls my method Log(), not Zend_log->log() and it will always add records to my main logger, not crons logger.
Am I missing something or calling something in incorrect way?
You're accessing the logger using $this->logger, which is not a static way to access it. Since it's a static variable, you got to use self:: just like you did got getLogger, so:
private function __construct()
{
// initialize logger
$writer = new Zend_Log_Writer_Stream(LOG_PATH);
self::$_logger = new Zend_Log($writer);
}
I'm reading up on php design patterns, and I saw this code:
<?php
require_once("DB.php");
class DatabaseConnection
{
public static function get()
{
static $db = null;
if ( $db == null )
$db = new DatabaseConnection();
return $db;
}
private $_handle = null;
private function __construct()
{
$dsn = 'mysql://root:password#localhost/photos';
$this->_handle =& DB::Connect( $dsn, array() );
}
public function handle()
{
return $this->_handle;
}
}
print( "Handle = ".DatabaseConnection::get()->handle()."\n" );
print( "Handle = ".DatabaseConnection::get()->handle()."\n" );
?>
I understand it all except the last two print statements. I've been messing around with it, but I don't understand the static function somehow calling a public non-static function.
I've notice I can do:
DatabaseConnection::get()->get()->get()->handle();
but I can't so something like:
DatabaseConnection::get()->handle()->get();
I just don't understand what this is doing, other than calling the get function then calling the handle function.
This works because the static function returns a new object. This type of construction is typically referred to as a Singleton, since it is attempting to enforce that only one instance of a DatabaseConnection is ever available.
Notice that the constructor is private, so you cannot explicitly call new DatabaseConnection() unless you are already inside the class. Solutions utilizing a Singleton will have a property, initally null, that is then set to a non-null value upon object instantiation. The 'getInstance' (or get in this case) method will only return a new object if the property is null.
DatabaseConnection::get() creates an instance of DatabaseConnection and returns it.
So...
DatabaseConnection::get()->handle();
...could also be written as follows...
$db = DatabaseConnection::get();
$db->handle();
consider the following code scenario:
<?php
//widgetfactory.class.php
// define a class
class WidgetFactory
{
var $oink = 'moo';
}
?>
<?php
//this is index.php
include_once('widgetfactory.class.php');
// create a new object
//before creating object make sure that it already doesn't exist
if(!isset($WF))
{
$WF = new WidgetFactory();
}
?>
The widgetfactory class is in widgetfactoryclass.php file, I have included this file in my index.php file, all my site actions runs through index.php, i.e. for each action this file gets included, now I want to create object of widgetfactory class ONLY if already it doesn't exist. I am using isset() for this purpose, is there any other better alternative for this?
Using globals might be a way to achieve this. The common way to do this are singleton instances:
class WidgetFactory {
private static $instance = NULL;
static public function getInstance()
{
if (self::$instance === NULL)
self::$instance = new WidgetFactory();
return self::$instance;
}
/*
* Protected CTOR
*/
protected function __construct()
{
}
}
Then, later on, instead of checking for a global variable $WF, you can retrieve the instance like this:
$WF = WidgetFactory::getInstance();
The constructor of WidgetFactory is declared protected to ensure instances can only be created by WidgetFactory itself.
This should do the job:
if ( ($obj instanceof MyClass) != true ) {
$obj = new MyClass();
}
I have an object of some class that obeys the singleton pattern. I need to initialize it in one file and then use it in others. I don't know how to do this, here is what I tried :
//myClass.php
class myClass
{
private static $instance = null;
private function __construct($args)
{
//stuff
}
public function Create($args)
{
self::$instance = new myClass($args);
return self::$instance;
}
public function Get()
{
return self::$instance;
}
}
//index.php
<?php
require_once('myClass.php');
$instance = myClass::Create($args);
?>
Test Me!
//test.php
echo(is_null(myClass::Get())); //displays 1
So the problem is that from test.php, myClass::get() always returns null!
I have also tried to store the instance in the $_SESSION, which gives me the same result. Can you please point me in the right direction?
You should include file with the class difinition in each file where it used (and it should be included before it will in use).
<?php // filename: test.php
include_once("myClass.php");
$oClassInstance = myClass::Get();
var_dump($oClassInstance);
BTW
You don't need to define those two methods Create and Get. You can create only one method called getInstance:
// only one instance of the class
private static $_oInstance = null;
public static function getInstace()
{
if (!self::$_oInstance)
{
self::$_oInstance = new self();
}
return self::$_oInstance;
}
And then you can use it like:
<?php // filename: index.php
include_once("myClass.php");
// if instance does not exist yet then it will be created and returned
$oClass = myClass::getInstace();
<?php // filename: test.php
include_once("myClass.php");
// the instance already created and stored in myClass::$_oInstance variable
// so it just will be returned
$oClass = myClass::getInstance();
UPD
If you have to put some arguments into constructor just use predefined arguments:
private function __construct($aArg)
{
// this code will be launched once when instance is created
// in the any other cases you'll return already created object
}
public static function getInstance($aArgs = null)
{
if (!self::$_oInstance)
{
self::$_oInstance = new self($aArgs);
}
return self::$_oInstance;
}
ANSWER
Sorry that you have to scroll a few screens to find this =)))
The reason why you can't use myClass::Get() in you context is that you have 2 scripts that means - two different programs.
Singleton should be used within a single application (one script).
So in your case, correct usage will be module system:
- index.php
- main.php
- test.php
// file: index.php
include_once "myClass.php"
$module = $_GET["module"];
include_once $module ".php";
// file: main.php
$oClass = myClass::Create($someArgs);
var_dump($oClass); // you'll see you class body
// file: test.php
$oClass= myClass::Get();
var_dump($oClass); // you'll see the same class body as above
And your links will be:
index.php?module=main
index.php?module=test
The Create() function need to check whether $instance property already has a value before creating a new object. For example
public function Create()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
In test.php you can just call myClass::Create(), no need to have the Get() function at all
I've never developed before and I'm a bit puzzled, what is wrong with my syntax here?
private static $instance; //holder of Mongo_Wrapper
public $connected = true;
private $mongo = null; // The mongo connection affiliation
private $database = null; // The database we are working on
with this function:
public function mongo_connect($db_name) {
if (! self::connected) {
$this->mongo = new Mongo;
//TODO: error handle this whole sharade: throw new Kohana_Database_Exception('Cant connect', NULL, 503);
$this->connected = true;
}
$this->database = $this->mongo->$db_name; //set the database we are working on
return $connected;
}
I'm sorry, wmd-editor is giving me hell posting the code.
Thank you!
edit: $connected isn't static, the problem is it isn't working either with static or with $this. Also, this is a singleton class, I don't know if this is important or not.
edit: this is the rest of the code, here self and this worked properly:
public static function singleton($db_name) {
if (!isset(self::$instance)) {
$c = __CLASS__;
$this->$instance = new $c;
}
self::mongo_connect($db_name);
return self::$instance;
}
enter code here
if (! self::connected) {
is probably the cause of your error. You only use self when you are trying to access static class members (which connected is not), and you have to use the $-Sign at the beginning, otherwise you are asking for a class constant. So you either have to declare connected as static, or use $this-> to access it.
Take a look at static class members in the PHP manual!
Also you should really try to understand how OOP works, before writing code like this. PHP tells you that you cannot use $this, because you are not in a object context, which means that you never created an object instance using the new.
Maybe the PHP OOP Basics will help you.
Unfortunately, PHP lets you call methods statically which aren't actually, which may be causing the error here. But sooner or later (probably sooner) you will need to understand the OOP basics anyway, so play around with a few simple classes before trying to write code for productive use.
Also take a look at this sample implementation of the singleton pattern.
If you need further help on this issue, please show us how you are calling the connect method!
There we have your problem. Your are doing the following:
self::mongo_connect($db_name);
Which means "call mongo_connect statically on self".
What you actually need to do is:
self::$instance->mongo_connect();
Which is equivalent to "call mongo_connect on the singleton instance of self".
But please take a closer look on a basic PHP tutorial, because what you are doing there in your code is mostly wrong...
$this->$instance = new $c;
Is wrong in so many ways... Not only because you are using $this in a static context, but also because you are assigning the created instance to a class member with the name which is *contained in $instance, which seems to be empty... No clue how this can actually work...
x3ro is right. You also need the $this->connected syntax at the end:
return $this->connected;
If you're getting an error message when you use $this->connected, it's because your function isn't a method on the class, but a global function.
self should be used with static members (use $this->connected instead of self::connected).
UPDATE
private static function mongo_connect($db_name, $instance)
{
if (!$instance->connected) {
....
}
...
return $instance->connected;
}
public static function singleton($db_name) {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
self::mongo_connect($db_name, self::$instance );
return self::$instance;
}