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();
}
Related
Let me know if you have a better title for this question :)
Up till now, I've created my factory class by doing this:
include_once('menu.class.php');
include_once('gallery.class.php');
class Factory {
function new_menu_obj() { return new Menu(Conn::get_conn()); }
function new_gallery_obj($type ='', $id='') { return new Gallery(Conn::get_conn(), $type, $id); }
/* Many more defined functions here */
}
class Conn { // DB connection }
// To create a new class object I just do this
$menu = Factory::new_menu_obj();
$gallery= Factory::new_gallery_obj('some-type','3');
Now I'm trying to do this more dynamically by using this code:
include_once('menu.class.php');
include_once('gallery.class.php');
class Factory {
private $db_conn;
private function __construct() {
$this->db_conn = Conn::get_conn();
}
public function create( $class_name ) {
if ( $this->db_conn === null ) {
$this->db_conn = Conn::get_conn();
}
return new $class_name( $this->db_conn );
}
}
class Conn { // DB connection }
// To create a new class object I just do this
$menu = Factory->create("Menu");
$gallery= Factory->create("Gallery"); // How do I pass more parameters here?
Is this the "correct way" of being efficient? :)
How can I create a new object passing variables when I do not know how many variables needs to be passed? Using a array?
1 - Factory->anything will fail, I guess you mean Factory::something in your code. Anyway, with a private constructor, you won't be able to create any instance of the Factory class outside of some static Factory method...
2 - since you use static methods, use the static keyword in your function declaration should be wise.
3 - as a side and personnal note, I'm not sure why you would want to do that. The first flavour of your class does a real factory job : it creates a consistent set of classes. And you will use another flavour of factory to create another set of similar but still consistent classes.
E.g. the Factory class creates Menu and Gallery instances, the AltFactory class creates AltMenu and AltGallery instances and so on.
But you loose this benefit with the second version of your factory. Just calling the new operator on your classes instead of calling your create construct will give you exactly the same degree of dependencies, so...
Using reflection and adding a $params parameter to your create method:
class Factory {
private $db_conn;
private function __construct() {
$this->db_conn = Conn::get_conn();
}
public function create( $class_name, $params = []) {
if ( $this->db_conn === null ) {
$this->db_conn = Conn::get_conn();
}
array_unshift($params, $this->db_conn);
$reflect = new ReflectionClass($class_name);
return $reflect->newInstanceArgs($params);
}
}
class Conn { // DB connection }
$menu = Factory->create("Menu");
$gallery= Factory->create("Gallery", ['pics' => ... ])
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;
}
}
This is a very basic php question : suppose I have 3 files, file1, file2, file3.
In file1 I declare a class called Object. In file2, I have a method that instantiate Object, call it $object, and call this method Method
In file2, this method looks like
public function Method(){
$object = new Object;
...
require_once(file3);
$anotherobject = new AnotherObject;
$anotherobject->method();
}
Finally, in file 3 I declare another AnotherObject. So, if I have a method 'method' in file3, can I refer to $object's properties directly, or could I access ony the static method of Object ?
This is not how decent OOp should be programmed. Give each class its own file. As I understand it you have 3 files with classes in them and want to use a the instantiated objects. Use Dependency Injection to construct classes that depend on each other.
Example:
file1.php:
class Object
{
public function SomeMethod()
{
// do stuff
}
}
file2.php, uses instantiated object:
class OtherObject
{
private $object;
public function __construct(Object $object)
{
$this->object = $object;
}
// now use any public method on object
public AMethod()
{
$this->object->SomeMethod();
}
}
file3.php, uses multiple instantiated objects:
class ComplexObject
{
private $object;
private $otherobject;
public function __construct(Object $object, OtherObject $otherobject)
{
$this->object = $object;
$this->otherobject = $otherobject;
}
}
Tie all this together in a bootstrap file or some kind of program file:
program.php:
// with no autoloader present:
include_once 'file1.php';
include_once 'file2.php';
include_once 'file3.php';
$object = new Object();
$otherobject = new OtherObject( $object );
$complexobject = new ComplexObject( $object, $otherobject );
the scope of $object there is limited to the method of course. file 3 is called from the method, so I would think yes, if using include(). using require_once() from inside the method however, makes me ask other questions concerning the potential of file3 not being able to take advantage of the variables in the method shown if it is previously included elsewhere and therefore not included from within the method.
I need an idea to create anonymous class on PHP. I don't know how I can works.
See my limitations:
On PHP you can't make anonymous class, like anonymous function (like class {});
On PHP you don't have class scope (except in namespaces, but it have the same problem below);
On PHP you can't use variables to specify the class name (like class $name {});
I don't have access to install the runkit PECL.
What I need, and why:
Well, I need create a function called ie create_class() that receives a key name and a anonymous class. It'll be useful for me because I want use different name class symbols that PHP can't accept. For instance:
<?php
create_class('it.is.an.example', function() {
return class { ... }
});
$obj = create_object('it.is.an.example');
?>
So, I need an idea that accept this use. I need it because on my framework I have this path: /modules/site/_login/models/path/to/model.php. So, the model.php need to declare a new class called site.login/path.to.model.
On call create_object() if the internal cache have a $class definition (like it.is.an.example it simply return the new class object. If not, need load. So I will use the $class content to search fastly what is the class file.
In PHP 7.0 there will be anonymous classes. I don't fully understand your question, but your create_class() function might look like this:
function create_class(string $key, array &$repository) {
$obj = new class($key) {
private $key;
function __construct($key) {
$this->key = $key;
}
};
$repository[$key] = $obj;
return $obj;
}
This will instantiate an object with an anonymous class type and register it into the $repository. To get an object out you use the key you created it with: $repository['it.is.an.example'].
You can create a dummy class using stdClass
$the_obj = new stdClass();
So basically you want to implement a factory pattern.
Class Factory() {
static $cache = array();
public static getClass($class, Array $params = null) {
// Need to include the inc or php file in order to create the class
if (array_key_exists($class, self::$cache) {
throw new Exception("Class already exists");
}
self::$cache[$class] = $class;
return new $class($params);
}
}
public youClass1() {
public __construct(Array $params = null) {
...
}
}
Add a cache within to check for duplicates
If you really need to to that, you could use eval()
$code = "class {$className} { ... }";
eval($code);
$obj = new $className ();
But the gods won't approve this. You will go to hell if you do it.
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