Send interface to constructor PHP - php

I have downloaded an example for a payment connection. No i am trying to use it, but the constructor want's to get the interface when i declare ClassName
But i have no idea how to do that. I tried
$interface = CallbackInterface::class;
$interface = CallbackInterface();
$interface = CallbackInterface;
And many more , but i can't figure it out. Only thing i know is to implement an interface with a class. Maybe a noob question, but i've searched almost a day with no success.
$config = new Config('string1', 'string2');
$pay = new ClassName($config, $interface);
interface CallbackInterface
{
public function Key($sIdentifier, $sTransactionKey);
public function tSuccess($sTransactionKey);
}
class ClassName
{
public function __construct(Config $oConfig, CallbackInterface $oCallbacks)
{
$this->oConfig = $oConfig;
$this->oCallbacks = $oCallbacks;
}
}

you should be looking for a solution along these lines
// Create a class that implements the interface (e.g. MyClass)
// MyClass implements the interface functions: Key and tSuccess
// MyClass can now be injected as type CallbackInterface into the __construct() of class ClassName
Class MyClass implements CallbackInterface
{
public function Key($sIdentifier, $sTransactionKey)
{
// your implementation here
}
public function tSuccess($sTransactionKey)
{
// your implementation here
}
}
interface CallbackInterface
{
public function Key($sIdentifier, $sTransactionKey);
public function tSuccess($sTransactionKey);
}
class ClassName
{
public function __construct(Config $oConfig, CallbackInterface $oCallbacks)
{
$this->oConfig = $oConfig;
$this->oCallbacks = $oCallbacks;
}
}
$config = new Config('string1', 'string2');
$interface = new MyClass(); // you've now instantiated an object of type CallbackInterface
$pay = new ClassName($config, $interface);

Related

Factory Method: Prevent a class from Direct Instancing

I have a Factory Method to instance a class. Is there a way to prevent this class from direct instancing?
The only option I see is to use an argument passed into the __construct(), but that's not something I'm looking for.
On the other hand, making the __construct() private would be ideal, but I don't want MyClass to extend the Factory without actual need.
What do you guys think?
Factory Method:
class Factory
{
public static function instance()
{
return new MyClass(true);
}
}
MyClass:
class MyClass
{
public function __construct($isFactory = false)
{
if (!$isFactory) {
throw new Exception('Use Factory::instance() to create an object');
}
}
}
There are hacks to do that:
abusing inheritance to use a protected constructor
putting the factory method inside the class so that it can call the private constructor, which is actually not a hack. But then why not using the constructor in the first place?
using reflection to access the private constructor
I'm not promoting anything of that. What I personally do is documenting the API with things like #internal and leave it to the client following that contract.
In essence, your code should have read something like this:
THE FACTORY
<?php
class Factory {
public static function instance(){
return new MyClass(true); //HERE YOU ARE INSTANTIATING
}
}
THE CLASS TO BE INSTANTIATED VIA THE FACTORY
<?php
//NOT MyClass() <--- YOU ARE DEFINING.... NOT INSTANTIATING...
class MyClass {
public function __construct($isFactory = false) {
if (!$isFactory) {
throw new Exception('Use Factory::instance() to create an object');
}
}
//...MORE METHODS
}
Could you try this instead?
<?php
class Factory
{
private static $FACTORY_GUARANTOR; //ONLY SET DURING INSTANTIATION
public static function instance($type) {
if (class_exists($type)) {
self::$FACTORY_GUARANTOR = 1;
$instance = new $type();
self::$FACTORY_GUARANTOR = null;
return $instance;
}
else {
throw new Exception("Class not found...");
}
}
//YOU CAN GET $FACTORYGUARANTOR EXTERNALLY BUT NEVER SET IT;
public static function getGuarantor(){
return self::$FACTORY_GUARANTOR;
}
}
class MyClass {
protected $property1;
protected $property3;
protected $property2;
public function __construct() {
// IF SOMEONE TRIES TO INSTANTIATE THE CLASS OUTSIDE OF THE FACTORY... BLOW A WHISTLE
if(!Factory::getGuarantor()){
throw new Exception('Use Factory::instance() to create an object');
}
// IF THE PROGRAM MADE IT TO THIS POINT;
// JUST INSTANTIATE THE CLASS BECAUSE MOST LIKELY IT IS COMING FROM THE FACTORY
var_dump($this); // A LITTLE CONFIRMATION....
}
//...MORE METHODS
}
// TRY IT OUT:
/*INSTANCE A: RIGHT*/ $theClass = Factory::instance("MyClass"); //INSTANTIATES THE CLASS
/*INSTANCE B: WRONG*/ $theClass = new MyClass(); //THROWS AN EXCEPTION
The easiest way is to define your base class as abstract. The abstract classes cannot be directly instanced, so you will have to redefine their abstract members in the inherited classes:
abstract class Factory
{
abstract public function foo();
}
class InheritedClass extends Factory
{
public function foo()
{
// Do something
}
}
// $obj1 = new Factory(); // Will produce an error
$obj1 = new InheritedClass(); // Will be executed successfully
You can read more for the abstract classes here: PHP: Class Abstraction - Manual.
For me, the best way is to use ReflectionClass:
class MyClass
{
public const FRIEND_CLASSES = [Factory::class];
protected function __construct() {}
}
trait Constructor
{
protected function createObject(string $className, array $args = [])
{
if (!in_array(static::class, $className::FRIEND_CLASSES)) {
throw new \Exception("Call to private or protected {$className}::__construct() from invalid context");
}
$reflection = new ReflectionClass($className);
$constructor = $reflection->getConstructor();
$constructor->setAccessible(true);
$object = $reflection->newInstanceWithoutConstructor();
$constructor->invokeArgs($object, $args);
return $object;
}
}
class Factory
{
use Constructor;
public function MyClass(): MyClass
{
return $this->createObject(MyClass::class);
}
}
In constant FRIEND_CLASSES you can define in which classes the class can be instanced.
trait is used because this functionality can be used in different factories that are not related.
If you need to put parameters into constructor of the class, put them as second parameter of createObject.
Details I described in the article "Forbidding of creating objects outside factory in PHP"

PHP Change parent class at runtime?

I have a parent class that depends on whether child class are instantiated.
class GoogleApp {
protected $auth_token;
public function __construct($scopes) {
$this->auth_token = $scopes;
}
}
class Gmail extends GoogleApp {
public function __construct() {
print_r($this->auth_token);
}
}
$googleApp = new GoogleApp('gmail'); // Change the actual class for all child instances
$gmail = new Gmail();
The idea is that all the children use the same auth_token (which is generated on whether the child classes are used - as of now, I'm just manually adding them to whether I included them in my code). Since I have quite a few child classes (like Calendar or Drive), do I have to inject the parent into each child instance or is there an easier way?
If I understand your request correctly, you're pretty close, you just need to declare your property as static.
class FooParent
{
protected static $scope = null;
public function __construct($scope)
{
self::$scope = $scope;
}
public function getScope()
{
return self::$scope;
}
}
class FooChild extends FooParent
{
public function __construct()
{
if (self::$scope === null) {
throw new Exception('Must set scope first.');
}
}
}
$parent = new FooParent('foo');
$child = new FooChild();
echo $child->getScope(), "\n"; // prints "foo"

Initiating a class globally

To be specific, i have a two class Request and Utils,
class Request
{
public function __construct()
{
//constructor method
}
public function request()
{
$utils=new Utils;
$consolidated_errors=$utils->array_remove_empty($all_params_error);
}
public function process()
{
$utils=new Utils;
$consolidated_errors=$utils->another_method($all_params_error);
}
}
And class Utils,
class Utils
{
public function __construct()
{
//constructor method
}
public function array_remove_empty()
{
//returns a variable.
}
public function another_method()
{
//returns a variable.
}
}
you can see that i am initializing the class two times in request class , and my question is that any way initializing the class globally and using through out the class?
You are looking for Singleton pattern
Following demonstrate very basic Singleton example for your class
public class Utils {
private static Utils uniqInstance;
private Utils() {
}
public static synchronized Utils getInstance() {
if (uniqInstance == null) {
uniqInstance = new Utils();
}
return uniqInstance;
}
// other useful methods here
}
get the instance using static-factory pattern
The above code does not look like Java to me, but anyway,
You could create the class at a class level private Utils myUtuils = new Utils ();
or
have the class as a static class and then just use it directly in your method
public function process()
{
consolidated_errors= Utils.another_method($all_params_error);
}
}

Can I reuse decorators?

Can I reuse decorators?
I have a ClientDecorator to decorate an entity that has a reference of a client, this decorator gets the client on database on call getClient (before it gets decorated, this method returns the clientId, after being decorated, it returns an instance of Client).
Okay, but, I've some other entities that can be decorated with the same decorator, for example, I have another table named questions, this table has a reference pointing to a client that has asked a question, and I have another table named schedules, that has a reference of a client.
By the way, I can decorate question and schedule with ClientDecorator.
But, I have an QuestionDecorator too; this guy decorates an Answer, etc.
How I can do this abstraction, so I can reuse decorators whenever I want?
I've tried to create ClientDecorable, QuestionDecorable interfaces, but have made no progress.
You can always instance the decorator class passing parameters to the constructor that will tell it how it should behave or what class it should impersonate. You don't really have to declare your decorator as an extension of another class.
PHP classes support magic methods that make it possible to forward calls to the class your object is impersonating, just as if it was extending it with extends.
For instance:
class Client
{
public function getId() { return 123; }
}
class Decorator
{
private $instance = null;
public function __construct($class)
{
$this->instance = new $class();
}
public function __call($method, $params) // magic method
{
return call_user_func_array(array($this->instance, $method), $params);
}
}
$object = Decorator('Client');
echo $object->getId(); // 123
The magic method __call() will be invoked when you try to access a method that doesn't belong to the class Decorator. The same can be done with properties by using the magic methods __get() and __set().
That's a really tricky problem. I could find a solution, but it is kind of McGiver style... Works for PHP 5.4+ (yes, traits).
<?php
interface Decorable
{
public function getTarget();
}
interface ClientDecorable extends Decorable
{
public function getClient();
}
interface LogDecorable extends Decorable
{
public function getLog();
}
abstract class AbstractDecorator implements Decorable
{
private $target;
public function __construct(ClientDecorable $target)
{
$this->target = $target;
}
public function getTarget()
{
// I'll be able to access the leaf node of my decorator single way 'tree'
return $this->target->getTarget();
}
public function __call($method, $args) {
$reflected = new ReflectionClass($this->target);
if ($reflected->hasMethod($method)) {
return call_user_func_array([$this->target, $method], $args);
}
}
}
class ClientDecorator extends AbstractDecorator implements ClientDecorable
{
public function __construct(Decorable $target) {
if (! $target->getTarget() instanceof ClientDecorable) {
throw new Exception('Must be an instance de ClientDecorable');
}
parent::__construct($target);
}
public function getClient()
{
return new Client($this->getTarget()->getClient());
}
}
class LogDecorator extends AbstractDecorator implements LogDecorable
{
public function __construct(Decorable $target) {
if (! $target->getTarget() instanceof LogDecorable) {
throw new Exception('Must be an instance de LogDecorable');
}
parent::__construct($target);
}
public function getLog()
{
return new Log($this->getTarget()->getLog());
}
}
abstract class AbstractTarget implements Decorable
{
// this does the trick
public function getTarget() { return $this; }
}
trait ClientDecorableTrait {
public function getClient()
{
return $this->client;
}
}
trait LogDecorableTrait {
public function getLog()
{
return $this->log;
}
}
class Payment extends AbstractTarget implements ClientDecorable, LogDecorable
{
use ClientDecorableTrait;
use LogDecorableTrait;
private $client = 1;
private $log = 101;
}
class Sale extends AbstractTarget implements ClientDecorable
{
use ClientDecorableTrait;
private $client = 2;
}
class Client
{
// ...
}
class Log
{
// ...
}
$sale = new Sale();
var_dump($sale->getClient());
$saleDec = new ClientDecorator($sale);
var_dump($saleDec->getClient());
$payment = new Payment();
var_dump($payment->getClient());
$paymentDec = new ClientDecorator($payment);
var_dump($paymentDec->getClient());
var_dump($paymentDec->getLog());
$paymentDecTwice = new LogDecorator($paymentDec);
var_dump($paymentDecTwice->getLog());
$saleDecTwice = new LogDecorator($saleDec); // will throw an exception
This is just a skeleton, a real world implementation must be tricky. I think you'd better keep your decorators separated...

Testing a private method in an abstract class extends the other one

I'm trying to test a private method in an abstract class.
I've got three abstract classes:
abstract class AbstractClass1 extends AbstractClass2
{
private function _privateFunction()
{
//method's body
}
}
abstract class AbstractClass2 extends AbstractClass3
{
public function __construct($param)
{
parent::__construct($param)
}
}
abstract class AbstractClass3
{
public function __construct($param = array())
{
//something
}
}
The test class:
class AbstractClass1Test extends PHPUnit_Framework_TestCase
{
public function test_privateFunction()
{
$stub = $this->getMockForAbstractClass("AbstractClass1");
$class = new ReflectionClass($stub);
$method = $class->getMethod("_privateFunction");
$method->setAccessible(true);
//some assertings with $method->invoke($stub)
}
}
The test failed, because of the error:
Missing argument 1 for AbstractClass2::__construct(), called in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php on line 190 and defined
AbstractClass2.php
public function __construct($param)
AbstractClass1.php
$classMock = $this->getMockForAbstractClass("AbstractClass1");
Generator.php:190
if ($callOriginalConstructor &&
!interface_exists($originalClassName, $callAutoload)) {
if (count($arguments) == 0) {
<strong>$mockObject = new $mock['mockClassName'];</strong>
} else {
$mockClass = new ReflectionClass($mock['mockClassName']);
$mockObject = $mockClass->newInstanceArgs($arguments);
}
} else ...
What do I wrong? Or how can I test my private function in this situation?
You need to pass an argument to AbstractClass1's constructor. Pass constructor arguments in an array as the second argument to getMockForAbstractClass().
$stub = $this->getMockForAbstractClass("AbstractClass1", array('param'));
Seeing as you overrode the original constructor,
public function __construct($param = array()) //Allow null $param as it would default to array();
With a new one:
public function __construct($param) //Does not allow null $param.
You will require to define the $param when you initialize the object. That's probably your problem.
Objects in PHP are not like JavaScript, they cannot be called like associative arrays. Your object initialization should look like:
$mockObject = new ClassExtendingAbstractClass1Or2('parameter');
The new keyword cannot be used in front of a variable.

Categories