I have a core class as a collector and two subclasses stored in public variables in this core class:
class Core
{
public $cache;
public $html;
public function __construct()
{
$cache = new Cache();
$html = new Html();
}
}
class Cache
{
public function __construct()
{
}
public function store($value)
{
// do something
}
}
class Html
{
public $foo;
public function __construct()
{
$foo = "bar";
global $core;
$core->cache->store($foo);
}
}
QUESTION:
I would like to get rid of the line "global $core" and do something like:
$this->parent->cache->store($foo)
$cache should be connected to $core in some way because it is a public member of $core
I know that $html is a subclass stored as a variable and not an inheritance.
Any ideas?
Second question: Can I leave out the empty constructor in the Cache-Class?
What you can do is to use the concept of dependency injection to inject in your HTML class an object of the class Cache, and then, use it to call method store. I believe that this is a very good approach. So you can do something like this.
class Core
{
public $cache;
public $html;
public function __construct()
{
$cache = new Cache();
$html = new Html($cache);
}
}
In your class HTML:
class Html
{
public $foo;
public function __construct(Cache $cache)
{
$foo = "bar";
$cache->store($foo);
}
}
About your second question, if there is no necessity of do something in the constructor, you could just ommit it. But there is no problem to let it empty as well. So I think that it up to you.
Your object can't access caller class methods, because he do not know anything about it's caller.
You can try to pass parent when creating new object
class Core {
public $cache;
public $html;
public function __construct() {
$this->cache = new Cache($this);
$this->html = new Html($this);
}
}
class Html {
public $parent;
public function __construct($parent) {
$this->parent = $parent;
if (!empty($this->parent->cache)) {
$this->parent->cache->store();
}
}
}
Can I leave out the empty constructor - yes, you even do not have to declare __construct method at all, as all classes has it's default constructor/destructor.
Related
I have a hard time figuring out how to add a variable value to an instantiated class in php,
I've been looking at the reflectionClass and tried to return an assigned variable, and now I'm ended up with a getter setter.
I would really appreciate some help, here's an example of my code:
class controller
{
public $models;
private $load;
public function __construct()
{
$this->load = new loader();
}
public function action_being_run()
{
$this->load->set_model('model_name');
}
}
class loader
{
public function set_model($name)
{
{controller_class}->models[$name] = new model();
}
}
The controller class is instantiated without assigning it to a variable, but just:
new controller();
And then the action is executed from within the controller class.
You could pass a reference to $this into set_model()
class controller
{
public $models;
private $load;
public function __construct()
{
$this->load = new loader();
}
public function action_being_run()
{
$this->load->set_model('model_name', $this);
}
}
class loader
{
public function set_model($name, &$this)
{
{controller_class}->models[$name] = new model();
}
}
You also need to change public $model to public $models. There are probably other ways to achieve what you want, by either extending a class or just using magic methods to access the model.
Like this:
class tester{
public function lame(){
return 'super lame';
}
}
function after(){
return 'after function';
}
$tst = new tester; $tst->afterVar = 'anything'; $tst->afterFun = 'after';
echo $wh->afterVar;
echo $wh->afterFun();
Is it possible to declare an instance of a class as a property in PHP?
Basically what I want to achieve is:
abstract class ClassA()
{
static $property = new ClassB();
}
Well, I know I can't do that, but is there any workaround beside always doing something like this:
if (!isset(ClassA::$property)) ClassA::$property = new ClassB();
you can use a singleton like implementation:
<?php
class ClassA {
private static $instance;
public static function getInstance() {
if (!isset(self::$instance)) {
self::$instance = new ClassB();
}
return self::$instance;
}
}
?>
then you can reference the instance with:
ClassA::getInstance()->someClassBMethod();
An alternative solution, a static constructor, is something along the lines of
<?php
abstract class ClassA {
static $property;
public static function init() {
self::$property = new ClassB();
}
} ClassA::init();
?>
Please note that the class doesn't have to be abstract for this to work.
See also How to initialize static variables and https://stackoverflow.com/a/3313137/118153.
This is a few years old, but I just ran into a issue where I have a base class
class GeneralObject
{
protected static $_instance;
public static function getInstance()
{
$class = get_called_class();
if(!isset(self::$_instance))
{
self::$_instance = new $class;
}
return self::$_instance;
}
}
That has a Child Class
class Master extends GeneralObject
{
}
And another Child class
class Customer extends Master
{
}
But when I try to call
$master = Master::getInstance();
$customer = Customer::getInstance();
then $master will be Master as expected, but $customer will be Master because php uses the GeneralObject::$_instance for both Master and Customer
The only way I could achieve what I want was to change the GeneralObject::$_instance to be an array and adjust the getInstance() method.
class GeneralObject
{
protected static $_instance = array();
public static function getInstance()
{
$class = get_called_class();
if(!isset(self::$_instance[$class]))
{
self::$_instance[$class] = new $class;
}
return self::$_instance[$class];
}
}
I hope this helps someone else out there. Took me a few hours to debug what was going on.
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?
I am going to use singleton classes to manage both DB connections and references to application settings.
It seems a little messy to have to use the following code in every method in order to access the db class.
$db = DB::getInstance();
Is there a more efficient way of going about it?
Any advice appreciated.
Thanks
I often use the Registry pattern, where this behavior occurs as well. I always set a instance variable in the constructor of my models to point to the Registry entry;
class Registry {
private static $_instance;
private $_registry;
private function __construct() {
$_registry = array();
}
public static function getInstance() {
if (!Registry::$_instance) {
Registry::$_instance = new Registry();
}
return Registry::$_instance;
}
public function add($key, &$entry) {
$this->_registry[$key] = &$entry;
}
public function &get($key) {
return $this->_registry[$key];
}
public function has($key) {
return ($this->get($key) !== null);
}
}
Model example;
class MyModel {
private $_db;
public function __construct() {
$this->_db = Registry::getInstance()->get('dbKey');
}
/* Every function has now access to the DAL */
}
Instantiation example;
$dal = new Db(...);
Registry::getInstance()->add('dbKey', $dal);
...
$model = new MyModel();
$model->doDbStuff();
Another approach is to always pass the reference as a parameter to each constructor.
Of course I only use this behavior when most of the methods in my model use the reference, if only a few (one or two) methods have use of the reference, I call the Registry/Singleton like you showed.
It is not messy. This is an intended behavior of Singletons. And, actually, this is just one line of code. Do you wish to make it even more compact? :)
My preferred method is to create a Base class which all the classes that need db access descend from. Base calls the singleton(s) in its constructor. All its children call their parent constructor. e.g.:
class Base {
protected $db;
public function __construct(){
$this->db = DB::getInstance();
}
}
class Achild extends Base {
protected $var1;
public function __construct($arg){
parent::__construct();
$this->var1=$arg;
}
}
I know what you mean... hate that ::getInstance() stuff! So go and use static methods:
class DB {
private static $db;
public static function getInstance() {
if(!self::$db) {
self::$db = new DBconnector();
}
}
public static function query($query) {
return self::$db->query($query);
}
}
Usage is much nicer:
$result = DB::query('SELECT whatever;');
And if you use PHP 5.3 you can write a __callStatic similar to this, to forward all the method calls to the object:
public static function __callStatic($method, $args) {
call_user_func_array(array(self::$db, $method), $args);
}
And to make me happy, add an __autoloader so that you can access DB without any worries any time!
I have a class for interacting with a memcache server. I have different functions for inserting, deleting and retrieving data. Originally each function made a call to memcache_connect(), however that was unnecessary, e.g.:
mc->insert()
mc->get()
mc->delete()
would make three memcache connections. I worked around this by creating a construct for the class:
function __construct() {
$this->mem = memcache_connect( ... );
}
and then using $this->mem wherever the resource was needed, so each of the three functions use the same memcache_connect resource.
This is alright, however if I call the class inside other classes, e.g.:
class abc
{
function __construct() {
$this->mc = new cache_class;
}
}
class def
{
function __construct() {
$this->mc = new cache_class;
}
}
then it is still making two memcache_connect calls, when it only needs one.
I can do this with globals but I would prefer not to use them if I don't have to.
Example globals implementation:
$resource = memcache_connect( ... );
class cache_class
{
function insert() {
global $resource;
memcache_set( $resource , ... );
}
function get() {
global $resource;
return memcache_get( $resource , ... );
}
}
Then no matter how many times the class is called there will only be one call to memcache_connect.
Is there a way to do this or should I just use globals?
I would code another class using singleton pattern for getting the only instance of memcache. Like this -
class MemCache
{
private static $instance = false;
private function __construct() {}
public static function getInstance()
{
if(self::$instance === false)
{
self::$instance = memcache_connect();
}
return self::$instance;
}
}
and usage -
$mc = MemCache::getInstance();
memcache_get($mc, ...)
...
Pass in the MC instance:
class abc
{
function __construct($mc) {
$this->mc = $mc;
}
}
class def
{
function __construct($mc) {
$this->mc = $mc;
}
}
$mc = new cache_class;
$abc = new abc($mc);
etc.
I think you're looking for static properties here.
class mc {
private static $instance;
public static function getInstance() {
if (self::$instance== null) {
self::$instance= new self;
}
return self::$instance;
}
private function __construct() {
$this->mem = memcache_connect(...);
}
}
This implements a basic singleton pattern. Instead of constructing the object call mc::getInstance(). Have a look at singletons.
You should use dependency injection. The singleton pattern and static constructs are considered bad practice because they essentially are globals (and for good reason -- they cement you to using whatever class you instantiate as opposed to some other).
Here is something like what you should do in order to have easy maintenance.
class MemCache {
protected $memcache;
public function __construct(){
$this->memcache = memcache_connect();
}
}
class Client {
protected $MemCache;
public function __construct( MemCache $MemCache ){
$this->MemCache = $MemCache;
}
public function getMemCache(){
return $this->MemCache;
}
}
$MemCache = new MemCache();
$Client = new Client($MemCache);
$MemCache1 = $Client->getMemCache();
// $MemCache and $MemCache1 are the same object.
// memcache_connect() has not been called more than once.