I am writing a PHP class and have included a couple static functions for quick access as they are common for use and are simple in function. However they do use an object in them for database access. I will likely be using these static methods from both a static and non-static context throughout my code so I want to be able to test whether the function was called from a static or non-static context so that I can avoid creating a duplicate object if the function was called from a non-static context (this instance object and the one within the function to be used statically). Is there any way that I can test this in the function so that I can use the instance object if the function is called from a non-static context and create it's own object if the function is called from a static context?
Code Example:
class MyClass {
private $db;
function __constuct(){
$this->db = new DBConnect();
}
public static function myFunction(){
if(/* Is static */){
$db = new DBConnect();
} else {
$db =& $this->db;
}
// Do processing with $db, etc.
}
}
When a method is declared as static,
not only is the magic variable $this
unavailable (returns NULL), but it is
impossible to tell if the function was
actually called from a static context.
A backtrace implies that for a static
method, calling $object->method() is
internally translated to
className::method() at run time.
http://php.net/manual/en/language.oop5.static.php
You can check for non-static access only if you do not force the method to be static-only. Leave out the static keyword from the function declaration and test with:
public function myFunction(){
if(!isset($this)) {
(It can still be called as static function, even though you did not declare it as such.)
Bottom line - don't make classes which contain only static functions. It is not OOP, it is just your old procedural code masquerading as oop
If you are executing functions statically, there is no $this, as there is no object.
You will end up making the private $db a static variable too , and use it as self::$db.
That said, i would recommend to drop this pattern and write something like :
class Foobar
{
protected $_connection = null;
public function __construct( DBConnect $db )
{
$this->_connection = $db;
}
public function some_function()
{
$db = $this->_connection;
// Do processing with $db, etc.
}
}
And you use this class like this :
$db = new DBConnection( /* your password , user , host , etc. */);
$stuff = new FooBar( $db );
$stuff->some_function();
$blah = new DifferentClass( $db );
This way you share the same connection with all the classes that require it. And now the class FooBar is not responsible for making connection or has to know your connection details.
Solution 1: Make the $db variable private, and use it via a getter.
Solution 2: Implement a singleton pattern on the dbal side.
Even when calling a static method from an instance (not recommended), you do not have
access to $this, so your class will fatal.
class sns {
public static function moo() {
var_dump($this->fng);
}
public function goo() {
var_dump($this);
}
}
sns::moo();
$_ = new sns;
$_->moo();
$_->goo();
As another poster has indicated from the php manual.
$db however can be defined statically instead so it only needs to be created once regardless of whether the object is an instance or not.
Related
I have what seems like a simple query but I have not found an answer elsewhere.
I have 2 classes, one called DB which essentially connects to the database and can then run queries. I instantiate it at the top of the document $db= new DB; and I can then run a series of queries on the database throughout the page.
The issue I am having is that I want to use this instance within another class I have called User.
I know I can either instantiate again but this does not make sense OR pass the instance of DB when instantiating User, for instance $user = new User($db); but considering the $db instance will be used by most classes I am going to create I am thinking there is a better solution to import it into other classes.
I have looked at the global route but I read it is bad practice + I am getting unexpected global error
class User{
global $db;
public function __construct()
{
var_dump($this-> db);
}//end constructor
}//end class
Since your DB client will be instantiated once and then used everywhere else my initial thought was to recommend passing it as a constructor parameter (dependency injection), but since you are not fan of this approach, I would recommend making your DB client a singleton class, which means it can only be instantiated once and any subsequent attempt would return the same instance everywhere.
You can see a detailed response about singleton classes in PHP at Creating the Singleton design pattern in PHP5.
As a quick example, your DB would look like similar to this:
final class DB
{
public static function getInstance()
{
static $inst = null;
if ($inst === null) {
$inst = new self();
}
return $inst;
}
private function __construct()
{
// your code here ...
}
// your code here ...
}
And then, on your User class you would just get the DB class instance:
class User {
// your code here ...
public function doSomething() {
$db = DB::getInstance();
// your code here ...
}
}
PHP does not handle scopes like Javascript does, your $db is undefined.
The scope of a variable is the context within which it is defined. For the most part all PHP variables only have a single scope. This single scope spans included and required files as well […] Within user-defined functions a local function scope is introduced. Any variable used inside a function is by default limited to the local function scope.
Source: http://php.net/manual/en/language.variables.scope.php
This means that there is only a global scope and a function/method scope in PHP. So, either pass the $db instance into the method as a collaborator
class User{
public function __construct() {}
public function getInfo(Database $db) {
$db->query( /* ... */ );
}
}
$user = new User();
$db = new Database();
$user->getInfo($db);
or pass it in the constructor (dependency injection)
class User{
private $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function getInfo() {
$this->db->query( /* ... */);
}
}
$db = new Database();
$user = new User($db);
$user->getInfo();
I'm new to this level of PHP programming and I've been reading a post about singleton and static classes. I'm in the process of writing a class that would facilitate my DB connections.
I came across the following code by Jon Raphaelson (here) :
class ConnectionFactory
{
private static $factory;
public static function getFactory()
{
if (!self::$factory)
self::$factory = new ConnectionFactory(...);
return self::$factory;
}
private $db;
public function getConnection() {
if (!$this->db) // this line was modified due to comment
$this->db = new PDO(...); // this line was modified due to comment
return $db;
}
}
function getSomething()
{
$conn = ConnectionFactory::getFactory()->getConnection();
.
.
.
}
It seemed like I had found what I was looking for, however I have a few questions about it.
self::$factory = new ConnectionFactory(...); - I don't see a constructor in this class. Do I just create this constructor and pass in the db details ('dbname', 'user', 'pass', etc)?
the getSomething() function, I'm assuming that the intent was to put all of the actual functions that would retrieve data within the ConnectionFactory class - and this is the reason for this function being in this class. Otherwise, I would have expected this function to be within another class. [edit] SKIP THIS QUESTION, I didn't see the one bracket.
What happens when two users are logged into the site and are requesting the DB connection (both are doing updates, etc)? Will it be an issue that this is a singleton?
Thanks!
This is mostly to expand on my comments under the question...
The better "singleton" pattern would be this:
class ConnectionFactory {
protected static $connection;
public function getConnection() {
if (!self::$connection) {
self::$connection = new PDO(...);
}
return self::$connection;
}
}
The users of this factory should expect an instance of it, not call it themselves:
class Foo {
protected $connectionFactory;
public function __construct(ConnectionFactory $factory) {
$this->connectionFactory = $factory;
}
public function somethingThatNeedsAConnection() {
$connection = $this->connectionFactory->getConnection();
...
}
}
$foo = new Foo(new ConnectionFactory);
This allows Foo to get a connection itself when needed, but also allows you to inject some alternative connection into Foo, for example for testing purposes.
As a convenience measure and to cut down on instantiation complexity, this pattern is also good:
class Foo {
protected $connectionFactory;
public function __construct(ConnectionFactory $factory = null) {
if (!$factory) {
$factory = new ConnectionFactory;
}
$this->connectionFactory = $factory;
}
...
}
This still allows the dependency to be injected and overridden, but it doesn't require you to inject a factory every time you instantiate Foo.
The factory is a singleton because you're not want more than one factory.
You don't need a constructor, you can setup whatever state you need for the factory the getFactory() method. The getFactory() function doesn't get a connection, so don't do any connection related setup here, but not the connection object itself. Factories 'build instances' of classes for you to use, so you'd use the getConnection() method to set the state and construct the connection object the factory is supposed to generate.
getSomething() isn't a method in the ConnectionFactory class, it's just a example of using the factory class to get a factory, then get a connection.
I personally hate method chaining in PHP. What's really happening in getSomething() is:
function getSomething()
{
$factory = ConnectionFactory::getFactory();
$conn = $factory->getConnection();
.
.
.
}
A class doesn't need an explicit constructor in order to be instantiated with new ClassName(). However, if the class is supposed to be a singleton (and it looks like it in this case), the entire point of the pattern is making such instantiations impossible from outside of the class which is why I believe there should be a constructor declared with private keyword.
The get getSomething() is a "standalone" function with an example of using your class.
No. Multiple users use multiple instances of PHP processing your script and nothing is shared among them.
Let's say I have the following class:
class SQLMapper{
static find_user_by_id($id){
//sql logic here, using the $_DATABASE global to make a connection
}
}
I could simply call:
global $_DATABASE;
at the top of my function, but I don't want to do that for ALL of my static methods. Is there a way to get a static variable inside my class to reference the global $_DATABASE array?
EDIT: I can't assign it in the constructor, since this is all static, and the constructor is never called.
You can use the super-global array $_GLOBALS to access your $_DATABASE variable. For example:
query( $GLOBALS['_DATABASE'], 'some query' );
Alternatively, write a static function that returns the contents of that variable:
class SQLMapper
{
static function getDatabase()
{
global $_DATABASE;
return $_DATABASE;
}
static function find_user_by_id($id)
{
query( self::getDatabase(), 'some query' );
}
}
If it hurts, its likely that you're
doing it wrong.
First off, without seeing more of your code its impossible to provide a more concrete solution, but I would strongly recommend that you consider rearranging your class structure so that your static functions (it sounds like you've got a long list of them to implement) become non-static.
In essence, you should consider accessing an instantiated instance of SQLMapper and then calling the appropriate method from the instance. Using this paradigm, you could just instantiate a class level property for $_DATABASE which can then be freely referenced by all methods in the class.
For example:
class SQLMapper {
private $_db;
public function __construct()
{
global $_DATABASE;
$this->_db = $_DATABASE;
}
public function find_user_by_id($id) {
$sql = "Select * from User WHERE Id = ?";
$stmt = $this->_db->prepare($sql, $id);
return $stmt->execute();
}
}
With that said, using globals is generally a sign of poor code quality so I would also suggest that you consider taking a more object-oriented approach to your current design and look for tried and true methods for eliminating globals from your application altogether.
I'm not so sure I understand what you mean, sorry, but can you try using the static keyword?
I have a variable on the global scope that is named ${SYSTEM}, where SYSTEM is a defined constant. I've got a lot of classes with functions that need to have access to this variable and I'm finding it annoying declaring global ${SYSTEM}; every single time.
I tried declaring a class variable: public ${SYSTEM} = $GLOBALS[SYSTEM]; but this results in a syntax error which is weird because I have another class that declares class variables in this manner and seems to work fine. The only thing I can think of is that the constant isn't being recognised.
I have managed to pull this off with a constructor but I'm looking for a simpler solution before resorting to that.
EDIT
The global ${SYSTEM} variable is an array with a lot of other child arrays in it. Unfortunately there doesn't seem to be a way to get around using a constructor...
Ok, hopefully I've got the gist of what you're trying to achieve
<?php
// the global array you want to access
$GLOBALS['uname'] = array('kernel-name' => 'Linux', 'kernel-release' => '2.6.27-11-generic', 'machine' => 'i686');
// the defined constant used to reference the global var
define(_SYSTEM_, 'uname');
class Foo {
// a method where you'd liked to access the global var
public function bar() {
print_r($this->{_SYSTEM_});
}
// the magic happens here using php5 overloading
public function __get($d) {
return $GLOBALS[$d];
}
}
$foo = new Foo;
$foo->bar();
?>
This is how I access things globally without global.
class exampleGetInstance
{
private static $instance;
public $value1;
public $value2;
private function initialize()
{
$this->value1 = 'test value';
$this->value2 = 'test value2';
}
public function getInstance()
{
if (!isset(self::$instance))
{
$class = __CLASS__;
self::$instance = new $class();
self::$instance->initialize();
}
return self::$instance;
}
}
$myInstance = exampleGetInstance::getInstance();
echo $myInstance->value1;
$myInstance is now a reference to the instance of exampleGetInstance class.
Fixed formatting
You could use a constructor like this:
class Myclass {
public $classvar;
function Myclass() {
$this->classvar = $GLOBALS[SYSTEM];
}
}
EDIT: Thanks for pointing out the typo, Peter!
This works for array too. If assignment is not desired, taking the reference also works:
$this->classvar =& $GLOBALS[SYSTEM];
EDIT2: The following code was used to test this method and it worked on my system:
<?php
define('MYCONST', 'varname');
$varname = array("This is varname", "and array?");
class Myclass {
public $classvar;
function Myclass() {
$this->classvar =& $GLOBALS[MYCONST];
}
function printvar() {
echo $this->classvar[0];
echo $this->classvar[1];
}
};
$myobj = new Myclass;
$myobj->printvar();
?>
The direct specification of member variables can not contain any references to other variables (class {public $membervar = $outsidevar;} is invalid as well). Use a constructor instead.
However, as you are dealing with a constant, why don't you use php's constant or class constant facilities?
You're trying to do something really out-of-the-ordinary here, so you can expect it to be awkward. Working with globals is never pleasant, especially not with your dynamic name selection using SYSTEM constant. Personally I'd recommend you use $GLOBALS[SYSTEM] everywhere instead, or ...
$sys = $GLOBALS[SYSTEM];
... if you're going to use it alot.
You could also try the singleton pattern, although to some degree it is frowned upon in OOP circles, it is commonly referred to as the global variable of classes.
<?php
class Singleton {
// object instance
private static $instance;
// The protected construct prevents instantiating the class externally. The construct can be
// empty, or it can contain additional instructions...
protected function __construct() {
...
}
// The clone and wakeup methods prevents external instantiation of copies of the Singleton class,
// thus eliminating the possibility of duplicate objects. The methods can be empty, or
// can contain additional code (most probably generating error messages in response
// to attempts to call).
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Deserializing is not allowed.', E_USER_ERROR);
}
//This method must be static, and must return an instance of the object if the object
//does not already exist.
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
//One or more public methods that grant access to the Singleton object, and its private
//methods and properties via accessor methods.
public function GetSystemVar() {
...
}
}
//usage
Singleton::getInstance()->GetSystemVar();
?>
This example is slightly modified from wikipedia, but you can get the idea. Try googling the singleton pattern for more information
I'd say the first two things that stand out to me are:
You don't need the brackets around the variable name, you can simply do public $system or public $SYSTEM.
While PHP may not always require it it is standard practice to encapsulate non-numeric array indexes in single or double quotes in case the string you're using becomes a constant at some point.
This should be what you're looking for
class SomeClass {
public $system = $GLOBALS['system'];
}
You can also use class constants which would instead be
class SomeClass {
const SYSTEM = $GLOBALS['system'];
}
This can be referenced within the class with 'self::SYSTEM' and externally with 'SomeClass::SYSTEM'.
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?
__construct() would only be called if you called it from within a 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(self::$Connection))
{
self::$Connection = new DBConnection();
}
return self::$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.
Edit: Added $, as suggested by #emanuele-del-grande