I have custom class with DI ImapClient $imapClient:
class MailBoxCleaner
{
public function __construct(ImapClient $imapClient)
{
}
}
And there is an facade class:
class ImapConnection {
public function __construct()
{
return new ImapClient();
}
}
I tried to use this like:
$MailBoxCleaner = new MailBoxCleaner(new ImapConnection());
But it does not work.
A constructor never return any data.
You have to create a getter method that return the instance of your ImapClient class, so you inject it in the other class.
Based on your code :
class ImapConnection {
private $imapClient = null;
public function __construct()
{
$this->imapClient = new ImapClient();
}
public function getImapClient(){
return $this->imapClient;
}
}
You can inject :
$idObj = new ImapConnection(); // Instanciation
$MailBoxCleaner = new MailBoxCleaner($idObj->get());
You also can use a "pattern" :
class ImapConnection {
private $instance = null;
private $imapClient = null;
private function __construct()
{
$this->imapClient = new ImapClient();
}
public static function getImapClient(){
if(is_null($this->instance){
$this->instance = new ImapConnection();
}
return $this->instance->get();
}
private function get(){
return $this->imapClient;
}
}
Then, you can use in your code :
$MailBoxCleaner = new MailBoxCleaner(ImapConnection::getImapClient());
Related
I am trying to pass a class as a parameter but I do not know if it is possible.
class User {
var $name;
}
class UserRepository {
private $type;
public function __construct(Class) {
$this->type = Class;
}
public function getInstance() {
return new $this->type;
}
}
$obj = new UserRepository(User);
I am accepting suggestions on other ways to do it as well.
Just instantiate the class and call that
$user = new User();
$obj = new UserRepository($user);
Another option (since User contains only variables) is to make the variable static and use that
class User {
public static $name;
}
$obj = new UserRepository(User::$name);
I think you are just looking for a string:
class User {
var $name;
}
class UserRepository {
private $type;
public function __construct($Class) {
^^^^^^ this will be a string
$this->type = $Class;
}
public function getInstance() {
return new $this->type;
}
}
$obj = new UserRepository('User');
^^^^^^ send a string here
var_dump($obj->getInstance());
output:
object(User)#2 (1) { ["name"]=> NULL }
An example.
in this below class i want to use class like with static methods and for use class methods without create new object from parent.
for example:
<?php
class Permission
{
protected $permission = false;
protected $id = 0;
public static function __construct()
{
return new static;
}
public function user( $id )
{
$this->id = $id;
}
public function check()
{
$this->permission = true;
}
public function item( $item )
{
return $item;
}
}
$bar = Permission::user(100)->item("HELLO");
print_r($bar);
this code not working and have problem. how to resolve this class problem?
That will not work because user method is not static, try changing this two methods, and this is good way of generating objects
public function __construct($id)
{
$this->id = $id;
}
public static function user( $id )
{
return new static($id);
}
I'd suggest you a singleton pattern, like this
class Permission
{
static protected $permission = false;
static protected $id = 0;
private static $_instance = null;
private function __construct () { }
public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new self;
}
return self::$_instance;
}
public static function user( $userId )
{
self::$id = $userId;
return self::$_instance;
}
public static function check()
{
self::$permission = true;
return self::$_instance;
}
public static function item( $item )
{
return $item;
}
}
$bar = Permission::getInstance()->user(100)->item("HELLO");
print_r($bar);
You can chain methods in 'dynamic' classes by returning $this at the end of method (remember, you have a static).
class A {
public function someMethod()
{
// some code
return $this
}
public function otherMethod()
{
// some code
return $this
}
$a = new A();
$a->someMethod()->otherMethod();
}
If I have a setter and getter methods below :
<?php
class Name{
protected $first ;
public function setNameType($value) {
$this->first = $value;
}
public function getNameType() {
return $this->first;
}
}
$name = new Name;
$name->setNameType("My Name");
echo $name->getNameType();
?>
and a construct method like this
<?php
class Name{
protected $first ;
public function __construct($value) {
$this->first = $value;
}
public function getNameType() {
return $this->first;
}
}
$name = new Name("My Name");
echo $name->getNameType();
?>
Can I use the two interchangeably at all times or is there situations where one will be most prefered over the other ?
There is also some great explaination about your question: http://www.potstuck.com/2009/01/08/php-dependency-injection/
Try this website. It explains all with examples.
http://ralphschindler.com/2012/03/09/php-constructor-best-practices-and-the-prototype-pattern
Generally you would use constructors to set values if your class cannot exist or doesn't make sense without the value. If the value is allowed to be changed, than add a setter. If it should never be changed after construction, then don't add a setter.
An example code:
class Book {
public function __construct() {
$registry = RegistrySingleton::getInstance();
$this->_database = $registry->database;
// or
global $databaseConnection;
$this->_database = $database;
}
}
class Book {
private $_databaseConnection;
public function __construct() { }
public function setDatabaseConnection($databaseConnection) {
$this->_databaseConnection = $databaseConnection;
}
}
$book = new Book();
$book->setDatabase($databaseConnection);
$book = new Book($databaseConnection, $configFile);
$book = new Book();
$book->setDatabase($databaseConnection);
$book->setConfigFile($configFile);
class Container {
public static $_database;
public static function makeBook() {
$book = new Book();
$book->setDatabase(self::$_database);
// more injection...
return $book;
}
}
And then:
$book = Container::makeBook();
Bellow is a PHP script.
I tried to implement the Observer pattern (without MVC structure)... only basic.
The error which is encountered has been specified in a comment.
First I tried to add User objects to the UsersLibrary repository. There was a error such as User::update() does not exists or something.
Why is that error encountered? What fix should be applied and how?
interface IObserver {
public function update(IObservable $sender);
}
interface IObservable {
public function addObserver(IObserver $obj);
public function notify();
}
class UsersLibrary implements IObservable {
private $container;
private $contor;
//private $z;
public function __construct() {//IObserver $a) {
$this->container = array();
$this->contor = 0;
echo "<div>[constructing UsersLibrary...]</div>";
$this->addObserver(new Logger());
//$this->z = $a;
}
public function add($obj) {
echo "<div>[adding a new user...]</div>";
$this->container[$this->contor] = $obj;
$this->contor++;
$this->notify();
}
public function get($index) {
return $this->container[$index];
}
public function addObserver(IObserver $obj) {
$this->container[] = $obj;
}
public function notify() {
echo "<div>[notification in progress...]</div>";
foreach($this->container as $temp) {
//echo $temp;
#################################################################
$temp->update(); //--------ERROR
//Fatal Error: Call to a member function update() on a non-object.
#################################################################
}
//$this->container[0]->update();
//$this->z->update($this);
}
}
class User {
private $id;
private $name;
public function __construct($id, $name) {
$this->id = $id;
$this->name = $name;
}
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
}
class Logger implements IObserver {
public function __construct() {
echo "<div>[constructing Logger...]</div>";
}
public function update(IObservable $sender) {
echo "<div>A new user has been added.</div>";
}
}
$a = new UsersLibrary(); //new Logger());
//$a->add(new User(1, "DemoUser1"));
//$a->add(new User(2, "DemoUser2"));
$a->add("Demo");
echo $a->get(0);
//echo $a->get(0)->getName();
Your User class is not implementing interface IObserver and therefore is not forced to have the method update().
You have to instantiate a new User() in order to add it to the UsersLibrary:
$library = new UsersLibrary();
$user = new User(1, "Demo");
$library->add($user);
Also, you are mixing Users and Loggers into your UsersLibrary container. Maybe think about separating the containers for them?
You are passing a string instead of an object in your $a->add() call. You should either pass in an object, or alter the code in UserLibrary::add() to wrap it's argument in an appropriate object (or do an object lookup of it sees a string, for instance find a user with that name).
$user = new User(1, "Demo");
$a = new UsersLibrary();
$a->add($user);
I have this code running on PHP 5.2.6
class Singleton {
static private $instance = false;
private $id = false;
protected function __construct() {
$this->id = uniqid();
}
static public function instance() {
if (!self :: $instance) {
self :: $instance = new self();
}
return self :: $instance;
}
public function get_id() {
return $this->id;
}
}
class Chucknorris extends Singleton {
}
echo "php version = ".phpversion()."<br>";
$singleton = Singleton::instance();
echo get_class($singleton)."<br>";
echo "singleton id = ".$singleton->get_id()."<br>";
$chucknorris = Chucknorris::instance();
echo get_class($chucknorris)."<br>";
echo "chucknorris id = ".$chucknorris->get_id()."<br>";
Here's the output
php version = 5.2.6
Singleton
singleton id = 4ea7dca7d8f23
Singleton
chucknorris id = 4ea7dca7d8f23
When I ask for an instance of Chucknorris, I always get the Singleton one. I'd like to find out a way to extend the Singleton.
I know we can use get_called_class method to do it but it comes only with PHP 5.3. Is there anyway I can extend a Singleton without redefining the design pattern in the extended classes ?
Your best bet in PHP < 5.3 is to use a Singleton Factory:
class Singleton
{
private $id = false;
public function __construct() {
$this->id = uniqid();
}
public function get_id() {
return $this->id;
}
}
class SingletonFactory
{
private static $instance_array = array();
public static function getInstance($class_name)
{
if (!isset(self::$instance_array[$class_name]))
{
self::$instance_array[$class_name] = new $class_name();
}
return self::$instance_array[$class_name];
}
}
class Chucknorris extends Singleton {}
$singleton = SingletonFactory::getInstance('Singleton');
echo get_class($singleton)."<br>";
echo "singleton id = ".$singleton->get_id()."<br>";
$chucknorris = SingletonFactory::getInstance('Chucknorris');
echo get_class($chucknorris)."<br>";
echo "chucknorris id = ".$chucknorris->get_id()."<br>";
The only downside here is that your Singleton constructor is public.. so that's a basic violation of that pattern.
Update:
Here's a version that removes the public constructor (warning: this is getting into messy/hacky/poor design territory)
class Singleton
{
private $id = false;
public function __construct() {
$back = debug_backtrace(false);
if (!isset($back[1]['class']) || $back[1]['class'] != 'SingletonFactory')
{
throw new Exception('Consturctor not available, use SingletonFactory::getInstance("CLASSNAME")');
}
$this->id = uniqid();
}
public function get_id() {
return $this->id;
}
}
class SingletonFactory
{
private static $instance_array = array();
public static function getInstance($class_name)
{
if (!isset(self::$instance_array[$class_name]))
{
self::$instance_array[$class_name] = new $class_name($class_name);
}
return self::$instance_array[$class_name];
}
}
class Chucknorris extends Singleton {}
$singleton = SingletonFactory::getInstance('Singleton');
echo get_class($singleton)."<br>";
echo "singleton id = ".$singleton->get_id()."<br>";
$chucknorris = SingletonFactory::getInstance('Chucknorris');
echo get_class($chucknorris)."<br>";
echo "chucknorris id = ".$chucknorris->get_id()."<br>";
$badchuck = new Chucknorris(); // Exception!
Why don't you simulate the get_class_function if it doesn't exist with 5.3 PHP version ?
This code may answer your question.
if (!function_exists('get_called_class')) {
function get_called_class() {
$bt = debug_backtrace();
$lines = file($bt[1]['file']);
preg_match(
'/([a-zA-Z0-9\_]+)::'.$bt[1]['function'].'/',
$lines[$bt[1]['line']-1],
$matches
);
return $matches[1];
}
}
abstract class Singleton {
private $id = false;
protected function __construct() {
$this->id = uniqid();
}
static public function instance() {
static $instances = array();
$called_class_name = get_called_class();
if (!isset($instances[$called_class_name])) {
$instances[$called_class_name] = new $called_class_name();
}
return $instances[$called_class_name];
}
public function get_id() {
return $this->id;
}
}
class Chucknorris extends Singleton {}
class Brucelee extends Singleton {}
echo "php version = ".phpversion()."<br>";
$chucknorris = Chucknorris::instance();
echo get_class($chucknorris)."<br>";
echo "chucknorris id = ".$chucknorris->get_id()."<br>";
$brucelee = Brucelee::instance();
echo get_class($brucelee)."<br>";
echo "brucelee id = ".$brucelee->get_id()."<br>";
You can redefine just the getinstance method (and the instance itself) in Chucknorris to get an instance of it instead of the parent, but I'm not exactly sure what your end goal is. Just change the extending class to:
class Chucknorris extends Singleton {
static private $instance = false;
static public function instance()
{
if (!self :: $instance) {
self :: $instance = new self();
}
return self :: $instance;
}
}
Is this what you want? And if so - what is the reason you want it? I could think of a few, but would be glad if you share you goal.
Your code will most likely work if you move static private $instance = false; to the subclass and make it protected instead of private.
You also need to replace self:: with static:: so the static var is set in the subclass.
This requires PHP 5.3 - however, this shouldn't be a problem because PHP 5.2 reached end-of-life/support (that includes security updates!) as of january 2011!