I'm new in OO php, and I'm trying to access $my_array string (or it is a property):
class Something extends MAIN
{
private static $instance;
public static function newInstance()
{
if( !self::$instance instanceof self ) {
self::$instance = new self;
}
return self::$instance;
}
function __construct()
{
parent::__construct();
$my_array = array('test1','test2');
}
}
Tried with this:
$int = Something::newInstance();
echo $int->my_array;
echo Something::my_array
But nothing works. What is the problem? EDIT: I must mention that I shouldn't change anything inside Something class. Or it is impossible to do this without making a change inside Soemthing class?
$my_array is local to the constructor . You'll need to declare it in such a way that it has the scope of class. You'll have to do it as
class Something extends MAIN
{
private static $instance;
public $my_array = array();
// Rest code
}
$my_array is now a local variable in your method (=function in a class) and therefor cannot be read outside of that method. Change it like this to make it a 'property'*) of the object.
class Something extends MAIN
{
private static $instance;
public $my_array;
function newInstance() { ... } // Left out for brevity
function __construct()
{
parent::__construct();
// Use $this to reference the instance, in the way that self references the class.
$this->my_array = array('test1','test2');
}
}
Then use
$int = Something::newInstance();
echo $int->my_array;
*) PHP calls it a property, but in most languages a property is a definition that referes to getter and setter methods or directly to an (often private) variable in the class. In PHP, that variable itself is called a property.
class Something extends MAIN {
private static $instance;
public static $my_array;
public static
function newInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
function __construct() {
parent::__construct();
self::$my_array = array('test1', 'test2');
}
}
You can assign a value to $my_array directly without to be in the constructor function.
public static $my_array = array('test1', 'test2');
and remove this line from constructor
self::$my_array = array('test1', 'test2');
When usage:
$int = Something::newInstance();
print_r(Something::$my_array);
Related
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();
I have problem about calling a static property of a class inside another class.
Class A {
public $property;
public function __construct( $prop ) {
$this->property = $prop;
}
public function returnValue(){
return static::$this->property;
}
}
Class B extends A {
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
$B->returnValue();
I expect to return This is first property But the Output is just the name a parameter input in __construct;
When I print_r( static::$this->property ); the output is just property_one
Just change:
return static::$this->property;
with:
return static::${$this->property};
Maybe like this?
<?php
Class A {
public $property;
public function __construct( $prop ) {
$this->property = $prop;
print static::${$this->property};
}
}
Class B extends A {
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
(I mean you can access (print,...) the property this way, but the constructor will return an object anyway.)
There are several issues here:
the static property $property_one is declared in class B, the A class's constructor won't have access to that property, nor can you guarantee this property to be present.
Granted, since PHP 5.3, late static binding is supported, but that doesn't change the fact that you're never going to be sure that some static property that just happens to be called whatever $this->property happens to be assigned. What if it's assigned an object? an int, or float?
You access a static property like this: static::$propery or self::$property. Note the $! When you write static::$this->property, you're expecting this to evaluate to self::property_one. You're clearly missing the $ sign.
The very least you need is self::${$this->property}. Check the PHP manual on variable variables.
You're attempting to return a string from a constructor function, that's not possible. A constructor must, must return an instance of the class. Any return statements that don't will be ignored.
To have access to a static property of a child class in the constructor, you can't but rely on the child's constructor:
Class A
{
public $property;
}
Class B extends A
{
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
public function __construct( $prop )
{
$this->property = $prop;
print self::${$this->property};
}
}
$B = new B( 'property_one' );
An alternative would be:
Class A
{
public $property;
public function __constructor($prop)
{
$this->property = $prop;
}
public function getProp()
{
return static::${$this->property};
}
}
Class B extends A
{
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
$B->getProp();
I'm using PDT and Aptana on Eclipse Indigo with PHP 5.3 and I want to create a singleton in a class.
By singleton, I mean I want to just have one instance of that object, and for other objects or classes to get that single instance via a function that returns that object (so this would mean I'm trying to create an object within the class that defines that object, ie: creating objA within the class objA)
I understand you can't just go a head and do this:
public $object = new Object();
with in a class definition, you have to define it in the constructor.
How can I go ahead and do this? I'm coming from Java, so it could be I'm confusing some basic stuff. Any help is greatly appreciated. Here's the code:
<?php
class Fetcher{
private static $fetcher = new Fetcher(); //this is where I get the unexpected "new" error
static function getFetcherInstance(){
return $this->$fetcher;
}
}
?>
Solved! Thanks for all the help guys!
try this:
<?php
class myclass{
private static $_instance = null;
public static function getInstance() {
if (self::$_instance === null) {
self::$_instance = new myclass();
}
return self::$_instance;
}
}
?>
and call it with:
<?php
$obj = myclass::getInstace();
?>
You cannot assign a class property in PHP like that. It must be a scalar, or array value, or the property must be set in a method call.
protected static $fetcher;
static function getFetcherInstance(){
if (!self::$fetcher) {
self::$fetcher = new Fetcher();
}
return self::$fetcher;
}
Also, notice that I did not use $this->, as that only works for object instances. To work with static values you need to use self:: when working within the class scope.
You might want to just read common design patterns on the php site. There are pretty good examples with good documentation:
http://www.php.net/manual/en/language.oop5.patterns.php
Else, a singleton is simply a method that returns one single instance of itself:
class MySingletonClass {
private static $mySingleton;
public function getInstance(){
if(MySingletonClass::$mySingleton == NULL){
MySingletonClass::$mySingleton = new MySingletonClass();
}
return MySingletonClass::$mySingleton;
}
}
Building on #periklis answer you might want separate singletons for different application scopes. For example, lets say you want a singleton of a database connection - fine. But what if you have TWO databases you need to connect too?
<?php
class Singleton
{
private static $instances = array();
public static function getInstance($name = 'default')
{
if ( ! isset(static::$instances[$name]))
{
static::$instances[$name] = new static();
}
return static::$instances[$name];
}
}
Class DB extends Singleton {}
$db_one = DB::getInstance('mysql');
$db_two = DB::getInstance('pgsql');
Alse define __clone method
class Fetcher {
protected static $instance;
private function __construct() {
/* something */
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new Fetcher();
}
return self::$instance;
}
private function __clone() {
/* if we want real singleton :) */
trigger_error('Cannot clone', E_USER_ERROR);
}
}
Basically implementing a singleton pattern means writing a class with a private constructor and a static method to build itself. Also check PHP site for it: http://www.php.net/manual/en/language.oop5.php and http://it2.php.net/manual/en/book.spl.php
class A {
protected $check;
private function __construct($args) {
}
static public function getSingleton($args) {
static $instance=null;
if (is_null($instance)) {
$instance=new A();
}
return $instance;
}
public function whoami() {
printf("%s\n",spl_object_hash($this));
}
}
$c=A::getSingleton("testarg");
$d=A::getSingleton("testarg");
$c->whoami(); // same object hash
$d->whoami(); // same object hash
$b= new A("otherargs"); // run time error
<?php
class MyObject {
private static $singleInstance;
private function __construct() {
if(!isset(self::$singleInstance)) {
self::$singleInstance = new MyObject;
}
}
public static function getSingleInstance() {
return self::$singleInstance;
}
}
?>
class MyClass {
private static $instance;
public static function getInstance() {
if( !isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
}
Then call get instance using
MyClass::getInstance();
I have a global variable outside my class = $MyNumber;
How do I declare this as a property in myClass?
For every method in my class, this is what I do:
class myClass() {
private function foo() {
$privateNumber = $GLOBALS['MyNumber'];
}
}
I want this
class myClass() {
//What goes here?
var $classNumber = ???//the global $MyNumber;
private function foo() {
$privateNumber = $this->classNumber;
}
}
EDIT: I want to create a variable based on the global $MyNumber but
modified before using it in the methods
something like: var $classNumber = global $MyNumber + 100;
You probably don't really want to be doing this, as it's going to be a nightmare to debug, but it seems to be possible. The key is the part where you assign by reference in the constructor.
$GLOBALS = array(
'MyNumber' => 1
);
class Foo {
protected $glob;
public function __construct() {
global $GLOBALS;
$this->glob =& $GLOBALS;
}
public function getGlob() {
return $this->glob['MyNumber'];
}
}
$f = new Foo;
echo $f->getGlob() . "\n";
$GLOBALS['MyNumber'] = 2;
echo $f->getGlob() . "\n";
The output will be
1
2
which indicates that it's being assigned by reference, not value.
As I said, it will be a nightmare to debug, so you really shouldn't do this. Have a read through the wikipedia article on encapsulation; basically, your object should ideally manage its own data and the methods in which that data is modified; even public properties are generally, IMHO, a bad idea.
Try to avoid globals, instead you can use something like this
class myClass() {
private $myNumber;
public function setNumber($number) {
$this->myNumber = $number;
}
}
Now you can call
$class = new myClass();
$class->setNumber('1234');
Simply use the global keyword.
e.g.:
class myClass() {
private function foo() {
global $MyNumber;
...
$MyNumber will then become accessible (and indeed modifyable) within that method.
However, the use of globals is often frowned upon (they can give off a bad code smell), so you might want to consider using a singleton class to store anything of this nature. (Then again, without knowing more about what you're trying to achieve this might be a very bad idea - a define could well be more useful.)
What I've experienced is that you can't assign your global variable to a class variable directly.
class myClass() {
public $var = $GLOBALS['variable'];
public function func() {
var_dump($this->var);
}
}
With the code right above, you get an error saying "Parse error: syntax error, unexpected '$GLOBALS'"
But if we do something like this,
class myClass() {
public $var = array();
public function __construct() {
$this->var = $GLOBALS['variable'];
}
public function func() {
var_dump($this->var);
}
}
Our code will work fine.
Where we assign a global variable to a class variable must be inside a function. And I've used constructor function for this.
So, you can access your global variable inside the every function of a class just using $this->var;
What about using constructor?
class myClass {
$myNumber = NULL;
public function __construct() {
global myNumber;
$this->myNumber = &myNumber;
}
public function foo() {
echo $this->myNumber;
}
}
Or much better this way (passing the global variable as parameter when inicializin the object - read only)
class myClass {
$myNumber = NULL;
public function __construct($myNumber) {
$this->myNumber = $myNumber;
}
public function foo() {
echo $this->myNumber;
}
}
$instance = new myClass($myNumber);
If you want to access a property from inside a class you should:
private $classNumber = 8;
I found that globals can be used as follows:
Create new class:
class globalObj{
public function glob(){
global $MyNumber;
return $this;
}
}
So, now the global is an object and can be used in the same way:
$this->glob();
class myClass
{
protected $foo;
public function __construct(&$var)
{
$this->foo = &$var;
}
public function foo()
{
return ++$this->foo;
}
}
I have a singleton factory and would like it to return a reference to the object instance so that I can use the singleton factory to destroy the instance and not have instances elsewhere in my code to survive.
Example of what I would like to be able to do:
$cat = CatFactory::getInstance();
$cat->talk(); //echos 'meow'
CatFactory::destructInstance();
$cat->talk(); //Error: Instance no longer exists
This could work:
<?php
class FooFactory
{
private static $foo;
private function __construct()
{
}
public static function getInstance()
{
return self::$foo ? self::$foo : (self::$foo = new FooFactory());
}
public static function destroyInstance()
{
self::$foo = null;
}
public function __call($fn, $args)
{
if (!method_exists(self::$foo, $fn) || $fn[0] == "_")
throw new BadMethodCallException("not callable");
call_user_func_array(array(self::$foo, $fn), $args);
}
# function hidden since it starts with an underscore
private function _listen()
{
}
# private function turned public by __call
private function speak($who, $what)
{
echo "$who said, '$what'\n";
}
}
$foo = FooFactory::getInstance();
$foo->speak("cat", "meow");
$foo->_listen(); # won't work, private function
FooFactory::destroyInstance();
$foo->speak("cow", "moo"); # won't work, instance destroyed
?>
Obviously it is a hack.
Based on the documentation for unset, I do not think that is possible. You cannot actually destroy an object, only a handle to it. If other variables are around that still hold a reference, the object will continue to live on.
You can accomplish what you want by having your Cat object enforce a private $destroyed property. PHP 5 passes objects by reference by default, so you don't have to worry about that part.
A work around would be creating a cat class
class cat
{
public $cat;
public function __construct()
{
$this->cat = CatFactory::getInstance();
}
public function __destruct()
{
CatFactory::destructInstance();
}
}
$cat = new cat();
$cat->cat->talk();
$cat->cat->talk();