I am currently building a little project with PHP whilst not using any static methods or global state.
My class' constructors currently look a little like this, I am just injecting the dependent objects upon creating an object instance.
class Something {
public function __construct(Name\Space\Object $object, Other\Name\Space $object2)
{
# Assign properties here
}
}
In one of my application's classes I need to create new instances of various objects through the calling of its methods. Something a little like below;
class Something {
public function getNewObject()
{
return new Name\Space\Object();
}
public function getNewObject2()
{
return new Name\Space\ObjectTwo();
}
}
Is this how it should be done whilst adhering to the standard rule of dependency injection?
I am unsure how else it could be done as if I inject the object into the constructor then I will only have one instance whereas I may need many within my application?
Thanks,
I believe that functions are first class objects in PHP, so this should work:
<?php
class MyClass {
function foo() {
return 'foo';
}
};
class MyOtherClass {
function __construct($klass) {
$this->klass = $klass;
}
function get_instance() {
return new $this->klass();
}
}
$factory = new MyOtherClass(MyClass);
$obj = $factory->get_instance();
?>
// <h1> value should equal foo
<h1><?php echo $obj->foo();?></h1>
Edit: Tested and works.
Related
I encountered something magical about laravel (4.2), that i really want explaind how it could be possible.
When i up a MessageBag Class in Class A
And Pass that variable to Class B, somehow Class B overrides the Class A MessageBag without me declaring it.
class ClassA {
public function test()
{
$msgBag = new \Illuminate\Support\MessageBag;
new ClassB($msgBag);
if($msgBag->any()) {
#This will trigger and spit out "Message from Class B"
dd($msgBag);
}else{
print('nope no messages');
}
}
}
class ClassB {
protected $msgBag;
function __construct(\Illuminate\Support\MessageBag $msgBag)
{
$this->msgBag = $msgBag;
$this->setMessage();
}
public function setMessage()
{
$this->msgBag->add('message', 'Message from Class B');
}
}
I tested the same thing with a normal object but that behaved like i expected it to.
class ClassA {
public function test()
{
$object = (object) ['class'=>'A'];
new ClassB($object);
dd($object->class); # Will return A
}
}
class ClassB {
protected $object;
function __construct($object)
{
$this->object = $object;
$this->setMessage();
}
public function setMessage()
{
$this->object = (object) ['class'=>'B'];
}
}
So obviously Laravel is doing something behind the seances to make this possible, but I haven't found it yet.
Does anyone know how to replicate this ?
There is no Laravel magic here. In PHP, objects behave as though they are passed by reference (although they technically are not, but that's not relevant here).
This means that in your first example, the MessageBag object you created is the same object as the as the one assigned to $this->msgBag in ClassB. Therefore, any modifications made to the object inside ClassB are going to be seen when you inspect the $msgBag object in the test() method in ClassA.
This is not the case in your second example, because in your setMessage() method, you override the first object with an entirely new one.
Basically everything is behaving as you would expect with normal PHP.
I want to implement the strategy design pattern using php:
interface dummy_function {
public function render();
}
class a implements dummy_function {
public function render() {
echo "class a\n";
// I want to acess x_main::dummy like: echo parent::dummy
}
}
class b implements dummy_function {
public function render() {
echo "class b\n";
// I want to acess x_main::dummy like: echo parent::dummy
}
}
class x_main {
public $dummy = "hello world";
public function setX_Function( dummy_function $funcname ) {
$this->x_function = $funcname;
}
public function render() {
$this->x_function->render();
}
}
$test = new x_main();
$test->setX_Function( new a() );
$test->render();
Inside my classes I want to access to some methods and variables defined in the main class. Unfortunatelly "parent" does not work to access contents from the class "x_main" inside the implementation classes.
A way i found is to give $this as parameter to the method "render", like:
class x_main {
[...]
public function render() {
$this->x_function->render( $this );
}
}
class a implements dummy_function {
public function render( $mainclass ) {
echo "class a\n";
echo $mainclass->dummy;
}
}
The next way i testest is to set the variable from the class main direcly into the implemented function, like:
class x_main {
[ ... ]
public function setX_Function( dummy_function $funcname ) {
$this->x_function = $funcname;
$this->x_function->dummy = $dummy;
}
}
class a implements dummy_function {
public function render() {
echo "class a\n";
echo $this->dummy;
}
}
Both solutions work, but I feel a bit confused if that's the best way to implement my desired idea. It looks extremly like a workaround but not like a real OO-programming.
I'm looking forward for your ideas.
Rehashing the comments above:
The two classes aren't related in any way, they certainly don't have a
parent relationship. One object holding an instance of another object
does not mean these two objects are in any sort of relationship with
one another. You simply need to explicitly pass data into your
dummy_function instance; e.g.: public function render(array $data).
Response:
In my first solution I put the whole mainclass as parameter to the
render function. So this is a solution that will work in any case. But
if there is definitivly no relationship between these two objects I
prefer my second solution by setting the parameters directly with
$this->x_function->dummy = $dummy;
Sorry to tell you that you're wrong there. Implicitly setting a property on an object is in no way a defined interface. And I'm not using this word in the sense of PHP's interface keyword, I mean this in the broader sense of specifying how two pieces of code can interact and cooperate.
You've done a good job of specifying and using an interface for the render() function, this greatly decreases code coupling and increases flexibility and testability. Now you're destroying this again by using undefined and brittle property assignments.
You need to make the passing data into render aspect part of your interface specification. For example:
interface dummy_function {
public function render(array $data);
}
Or:
interface dummy_function {
public function setData(array $data);
public function render();
}
Or better:
interface DummyData {
/**
* #return string
*/
public function getDummyData();
}
interface DummyRenderer {
public function render(DummyData $data);
}
With this you're:
explicitly specifying what format your data is in (string)
codifying where render() can get access to such data (it'll receive a DummyData object which has a getDummyData() method)
You don't need to guess what property names are involved or what structure the passed object has.
Let's imagine that we have Registry pattern...
<?php
class Registry
{
private static $objects = array();
private static $instance = null;
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
protected function _get($key) {
return ($this->objects[$key]) ? $this->objects[$key] : null;
}
protected function _set($key, $val) {
$this->objects[$key] = $val;
}
public static function get($key) {
return self::getInstance()->_get($key);
}
public static function set($key, $object) {
return self::getInstance()->_set($key, $object);
}
}
?>
Using this realization is really easy...
<?
Registry::set('db', $db_client);
Registry::set('redis', $redis_client);
//Using registered objects is really easy
Registry::get('db')->query("...");
Registry::get('redis')->get("...");
?>
But as you can see, we're adding instances into registry even if we don't need them (yes, it's all about performance).
So, the question is... How to modify Registry pattern to be able to do lazy instantiation?
Here is what I'm looking for...
<?
class Registry
{
private static $objects = array();
private static $instance = null;
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
protected function _db() {
if (!$this->objects['db']) {
$this->objects['db'] = new DatabaseAdapter(DB_HOST, DB_NAME, DB_USER, DB_PASSWORD);
}
return $this->objects['db'];
}
protected function _redis() {
if (!$this->objects['redis']) {
$this->objects['redis'] = new Redis(REDIS_HOST, REDIS_DB, REDIS_USER, REDIS_PASSWORD);
}
return $this->objects['redis'];
}
public static function db() {
return self::getInstance()->_db();
}
public static function redis() {
return self::getInstance()->_redis();
}
}
?>
As you can see, DatabaseAdapter() or Redis() will be created only in we'll request them. Everything seems to be ok, but as you can see it's not a standalone class because _db(), _redis() methods contains connection constants etc.
How to avoid it? How can I define registry method within registry class to separate Registy class and objects inside it?
I'm really sorry about my English, but I hope it is clear for you.
Thank you.
PS: All code above was written 1 min. ago and wasn't tested.
If you use global constants you will always have a dependency on the global scope. It doesnt matter where it is. Also, even if you do not use constants, you still have the dependency on the Database class inside the Registry. If you want to dissolve those dependencies, you could use Factory methods on the to be created classes:
public function get($service)
{
if( !this->_data[$service] ) {
// requires PHP 5.2.3
this->_data[$service] = call_user_func($service .'::create');
}
return this->_data[$service];
}
So if you do get('DB'), the code would try to call the static DB::create() method inside the class you intend to create. But like I said, if you use global Constants for the configuration, you would just move the problem into another class.
Your db class could look like this:
class DB
{
protected static $_config;
public static setConfig(array $config)
{
self::_config = $config;
}
public static create()
{
return new self(
self::config['host'],
self::config['db'],
self::config['user'],
self::config['pass']);
}
}
The configuration can be stored inside an external configuration file, which you load and set to the DB class during bootstrap, e.g.
DB::setConfig(parse_ini_file('/path/to/db-config.ini'));
The disadvantage of this is, you have to add create() methods all over the place and all classes must be able to store their own configuration. You could centralize these responsibilities into a Builder pattern. But if you do this, you are half way to implementing an IoC Container anyways, so check out the following resources:
Fabien Potencier: What is Dependency Injection
Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern
Design pattern – Inversion of control and Dependency injection
Note: You are using a "static" modifier for $objects - as you are working with an instance, this is probaby not necessary.
How can I define registry method within registry class to separate Registy class and objects inside it?
They are always separate: Each object inside the registry class is just a reference to the (independent) object. But if this question is about including the appropriate class definition (?) you may use the class_exists() function to load the class as soon as required.
BurninLeo
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'.
I have a base class in which I want to specify the methods a child class must have, but not implement them itself. However, the methods in a child class may have a different number of paramaters to the definition in the base class.
Having tried this with an abstract method, php doesn't allow this. Is it possible?
The child class's function can add extra, optional arguments to the signature without it causing errors:
abstract class Foo {
abstract function bar($a);
}
class NewFoo extends Foo {
function bar($a, $b = null) {
//do something
}
}
Short of specifying the abstract method with no parameters and requiring the subclassed method to access the args through func_get_args, I don't see how this would be possible.
I would say this is one of the weak points of PHP's object orientation, that it wasn't designed to handle this kind of use case. It just wasn't meant to allow overloaded methods for its
It is indeed possible to do what you're talking about as a kind of hack, in both the way mentioned above with:
func_get_args()
or, just (like the commenter mentioned) pass in an array of arguments. Alternately you could pass in an object that has your arguments as data members. Then you could extend the parameter/argument object for your child method.
The point is that PHP is a language that thrives on permissiveness and not restriction. Abstract classes have a very basic implementation in PHP. If you have the need for a lot of structure like this, then PHP really might not be the best language choice.
I don't think this is an answer that you will want to use in production as it will be fairly slow, but just for the sake of it I tried to write something using Reflection, which seems to work. You will still get an E_STRICT because method declarations in subclasses are apparently supposed to match.
class a {
protected $requiredMethodsInSubclass = array( 'method1', 'method2', 'method3' );
public function __construct() {
$reflObject = new ReflectionObject($this);
$className = $reflObject->getName();
if ($className == __CLASS__) {
//this class is being instanciated directly , so don't worry about any subclasses
return;
}
foreach ($this->requiredMethodsInSubclass as $methodName) {
try {
$reflMethod = $reflObject->getMethod($methodName);
} catch (ReflectionException $e) { //method not anywhere
trigger_error("Method $methodName is not declared in class " . __CLASS__ . " or subclass $className", E_USER_ERROR);
continue;
}
$declaringClass = $reflMethod->getDeclaringClass();
if ($declaringClass->getName() == __CLASS__) {
//method is declared in this class, not subclass
trigger_error("Method $methodName is not declared in subclass $className", E_USER_ERROR);
}
}
}
public function method1() {
}
public function method2($a) {
}
}
class b extends a {
public function __construct() {
parent::__construct();
//some stuff
}
public function method2($a, $b, $c) {
}
}
$b = new b();