I use the design pattern Decorator in PHP, and I've got a structure problem.
Here's a simple example to illustrate my problem :
interface MyInterface {
function showUsers($array);
function showUser($i);
}
class MyCLass implements MyInterface {
function showUsers($array)
{
foreach($array as $toto) {
$this->showUser($toto);
}
}
function showUser($i)
{
echo $i;
}
}
class MyCLassDecorator implements MyInterface {
private $inner;
public function __construct(MyInterface $inner)
{
$this->inner = $inner;
}
function showUsers($array)
{
$this->inner->showUsers($array);
}
function showUser($i)
{
echo "User: $i";
}
}
class MyCLassDecorator2 implements MyInterface {
private $inner;
public function __construct(MyInterface $inner)
{
$this->inner = $inner;
}
function showUsers($array)
{
$this->inner->showUsers($array);
}
function showUser($i)
{
$this->inner->showUser($i);
echo " is wonderful";
}
}
$myClass = new MyCLassDecorator2(new MyCLassDecorator(new MyCLass()));
$myClass->showUsers(["Alfred", "Bob", "Claire"]);
With this code, the methods showUser of MyClassDecorator & MyClassDecorator2 will never be called.
What can I do?
Is it forbidden to call another method of the same class? (Not really convenient to split my code)
Is there another way to do this?
Should I create one interface by method ?
Thanks a lot :)
EDIT:
Here is the solution that I finally used, although I'm not really satisfied of it...
I split my code not in methods but in interfaces(services)
Here it is :
interface IShowUsers {
function showUsers($array);
}
interface IShowUser {
function showUser($user);
}
class Services {
static $showUsers;
static $showUser;
}
class MyShowUsers implements IShowUsers {
function showUsers($array)
{
foreach($array as $toto) {
Services::$showUser->showUser($toto);
}
}
}
class MyShowUser implements IShowUser {
function showUser($user)
{
echo $user;
}
}
class MyShowUserDecorator implements IShowUser {
private $inner;
public function __construct(IShowUser $inner)
{
$this->inner = $inner;
}
function showUser($user)
{
echo "User: ";
$this->inner->showUser($user)
}
}
class MyShowUserDecorator2 implements IShowUser {
private $inner;
public function __construct(MyInterface $inner)
{
$this->inner = $inner;
}
function showUser($user)
{
$this->inner->showUser($user);
echo " is wonderful";
}
}
$myClass = new MyShowUserDecorator2(new MyShowUserDecorator(new MyShowUser()));
Services::$showUsers = new MyShosUsers();
Services::$showUser = new MyShowUserDecorator2(new MyShowUserDecorator(new MyShowUser()));
Services::$showUsers->showUsers(["Alfred", "Bob", "Claire"]);
If you have a better solution, I will be happy to know it :)
Of course, I use the decorator pattern to use these decorators in different ways in many projects like in these exemples:
//no decorators
Services::$showUser = new MyShowUser();
//only the first
Services::$showUser = new MyShowUserDecorator(new MyShowUser());
//only the second
Services::$showUser = new MyShowUserDecorator2(new MyShowUser());
So the extend not seems to be a good solution.
Thanks a lot again for giving the right way to do this :)
It seems to me you need to re-think this a bit. If you can provide a clear picture of what you're trying to accomplish then we can provide more insight. But to answer your question directly you can extend the class and then override the method.
http://sandbox.onlinephpfunctions.com/code/61c33b0ce98631986134bf78efcd0391f9b9ab67
<?php
interface MyInterface {
function showUsers($array);
function showUser($i);
}
class MyCLass implements MyInterface {
function showUsers($array = ["Alfred", "Bob", "Claire"])
{
foreach($array as $toto) {
$this->showUser($toto);
}
}
function showUser($i)
{
echo $i;
}
}
// Extend the class in order to override the methods.
class MyCLassDecorator extends MyCLass {
// Also, try removing this method to see what it does.
function showUsers($array = [1,2,3])
{
foreach($array as $toto) {
$this->showUser($toto);
}
}
function showUser($i)
{
echo "c'est la fete chez $i";
}
}
$myClass = new MyCLassDecorator();
$myClass->showUsers();
EDIT
Not sure if I'm being clear or not but the issue is you're expecting inheritance behaviour without using inheritance. How is MyCLass supposed to know about MyCLassDecorator::showUser?
foreach($array as $toto) {
// The issue is this line. You're mixing `decorator` and `inheritance`.
// You should re-think your design. This will not work.
$this->showUser($toto);
}
Related
I didn't find an answer to this question no where, so here it goes:
I normally create a protected/private function and public function as well to access the protected/private as a "trigger", is this a good practise or just a pointless excess of code?
Here is an example of what I'm talking about...
public function addData($data_c, $data_a)
{
if ($this->isUser()) {
$this->addDataDB($data_c, $data_a);
} else {
die;
}
}
private function addDataDB($data_c, $data_a)
{
$connect = self::connect_data();
$sql = "INSERT INTO `accounts`(...) VALUES (...)";
$s_network = $data_c['s_network'];
$country = $data_c['country'];
$group_name = $data_c['group_name'];
foreach ($data_a as $login_password) {
$account = explode(':', $login_password);
if (isset($account[0]) && !empty($account[0]) && isset($account[1]) && !empty($account[1])) {
$login = $this->encryptData($account[0]);
$password = $this->encryptData($account[1]);
if (!$this->checkDuplicates($login)) {
if ($stmt = $connect->prepare($sql)) {
$stmt->bind_param("sssssss", ...);
$stmt->execute();
}
$stmt->close();
}
}
}
$connect->close();
}
Thats not a bad idea, but the better way would be to create a new decorator class, which handles the secure access. In addition, it's a bad idea, to die - instead, you should throw an exception.
class A {
function addData(...) {
// ...
}
}
class SecureA extends A {
function addData {
if (...) {
throw new NotAllowedException(...);
}
parent::addData(...);
}
}
If you want to go a step further and make you code more cleaner, you should use an interface and don't extend from class A
interface InterfaceA {
function addData(...);
}
class A implements InterfaceA {
function addData(...) {
// ...
}
}
class SecureAccessA implements InterfaceA {
/**
* #var InterfaceA
*/
private $a;
public function __construct(InterfaceA $a) {
$this->a = $a;
}
function addData(...) {
if (...) {
throw new NotAllowedException(...);
}
$this->a->addData(...);
}
}
Doing this forces you to modify SecureAccessA, if you change the interface of InterfaceA. So you can't silently add functions to A, which are allowed to call, because you forgot to override them in the child class.
I understand that one can use interfaces to mandate the definition of a function, but I cannot find something that enables one to mandate function calls, such that e.g. if I create a class being a member of another class (via extends, etc), with a function, for that class to automatically ensure that mandatory functions are called in part with that function.
I mean, to clarify further:
class domain {
function isEmpty($input) {
//apply conditional logic and results
}
}
class test extends domain {
function addTestToDBTable($test) {
/**
* try to add but this class automatically makes it so that all rules of
* class domain must be passed before it can run
* - so essentially, I am no longer required to call those tests for each and
* every method
**/
}
}
Apologies if this appears incoherent by any means. Sure, it seems lazy but I want to be able to force context without having to concern abou
Update:
Okay, to clarify further: in PHP, if I extend and declare a __construct() for a child class, that child class will override the parent __construct(). I do not want this, I want the parent construct to remain and mandate whatever as it pleases just as the child class may do so also.
I guess it can be done in two different ways.
Aspect Oriented Programming
Have a look here https://github.com/AOP-PHP/AOP
Generate or write Proxy classes
A really simple example could be:
<?php
class A {
public function callMe() {
echo __METHOD__ . "\n";
}
}
class B extends A {
// prevents instantiation
public function __construct() {
}
public function shouldCallMe() {
echo __METHOD__ . "\n";
}
public static function newInstance() {
return new ABProxy();
}
}
class ABProxy {
private $b;
public function __construct() {
$this->b = new B();
}
public function __call($method, $args) {
$this->b->callMe();
return call_user_func_array(array($this->b, $method), $args);
}
}
// make the call
$b = B::newInstance();
$b->shouldCallMe();
// Outputs
// ------------------
// A::callMe
// B::shouldCallMe
Hopes this helps a bit.
Sounds like you want a Decorator.
See This answer for a detailed explanation on how to do it. Note that it does not require a class extension.
I would use a domain-validating decorator with some doc-block metaprogramming magic. But this is really a job for an entire library, which no doubt exists.
fiddle
<?php
class FooDomain {
public static function is_not_empty($input) {
return !empty($input);
}
}
class Foo {
/**
* #domain FooDomain::is_not_empty my_string
*/
public function print_string($my_string) {
echo $my_string . PHP_EOL;
}
}
$foo = new DomainValidator(new Foo());
$foo->print_string('Hello, world!');
try {
$foo->print_string(''); // throws a DomainException
} catch (\DomainException $e) {
echo 'Could not print an empty string...' . PHP_EOL;
}
// ---
class DomainValidator {
const DOMAIN_TAG = '#domain';
private $object;
public function __construct($object) {
$this->object = $object;
}
public function __call($function, $arguments) {
if (!$this->verify_domain($function, $arguments)) {
throw new \DomainException('Bad domain!');
}
return call_user_func_array(
array($this->object, $function),
$arguments
);
}
public function __get($name) {
return $this->object->name;
}
public function __set($name, $value) {
$this->object->name = $value;
}
private function verify_domain($function, $arguments) {
// Get reference to method
$method = new \ReflectionMethod($this->object, $function);
$domains = $this->get_domains($method->getDocComment());
$arguments = $this->parse_arguments(
$method->getParameters(),
$arguments
);
foreach ($domains as $domain) {
if (!call_user_func(
$domain['name'],
$arguments[$domain['parameter']]
)) {
return false;
}
}
return true;
}
private function get_domains($doc_block) {
$lines = explode("\n", $doc_block);
$domains = array();
$domain_tag = DomainValidator::DOMAIN_TAG . ' ';
foreach ($lines as $line) {
$has_domain = stristr($line, $domain_tag) !== false;
if ($has_domain) {
$domain_info = explode($domain_tag, $line);
$domain_info = explode(' ', $domain_info[1]);
$domains[] = array(
'name' => $domain_info[0],
'parameter' => $domain_info[1],
);
}
}
return $domains;
}
private function parse_arguments($parameters, $values) {
$ret = array();
for ($i = 0, $size = sizeof($values); $i < $size; $i++) {
$ret[$parameters[$i]->name] = $values[$i];
}
return $ret;
}
}
Output:
Hello, world!
Could not print an empty string...
I have the following PHP code as chain of resposibility, I am using PHP5.4.9.
abstract class Logger
{
protected $next;
public function next($next)
{
$this->next = $next;
return $this->next;
}
public function run(){
$this->invoke();
if(null!=$this->next){
$this->next->invoke();
}
}
abstract public function invoke();
}
class EmailLogger extends Logger
{
public function invoke()
{
print_r("email\n");
}
}
class DatabaseLogger extends Logger
{
public function invoke()
{
print_r("database\n");
}
}
class FileLogger extends Logger
{
public function invoke()
{
print_r("file \n");
}
}
$logger = new EmailLogger();
$logger->next(new DatabaseLogger())->next(new FileLogger());
$logger->run();
the expect output is:
email
database
file
but the actually output:
email
database
I hope to implement chain of resposibility design pattern by PHP language, one abstract class and three or more classes to do something as a chain. but only the first two object works.
Anyting missing? Or PHP can not use this coding style under PHP5.4.9?
Thanks.
Replace
public function run() {
$this->invoke ();
if (null != $this->next) {
$this->next->invoke();
}
}
With
public function run() {
$this->invoke ();
if (null != $this->next) {
$this->next->run ();
}
}
please try $this->next->invoke() change $this->next->run()
hello im still on learning mvc by makeing one, and today i realize that i have a miss on how things work.
class Framework
{
function __construct()
{
require 'libraries/language/l.php';
/*
$l['hello'] = 'hello';
$l['helloworld'] = 'helloworld';
etc
*/
}
}
class Controller extends Framework
{
function index()
{
#missing ?
echo $l;
}
}
ok the first question is how can i echo $l from my controller files ? is there a way to do that ?
edit* same for this.
function library( $lib ){
if (file_exists('libraries/lib.'. $lib .'.php')) {
require 'libraries/lib.'. $lib .'.php';
if (class_exists($lib)) {
$class = ucfirst($lib);
$$lib = new $class;
return TRUE;
}
if (!class_exists($lib)) {
return FALSE;
}
}
}
thanks for looking in.
Adam ramadhan
Pass the data through object protected properties:
class Framework
{
protected $l = array();
function __construct()
{
require 'libraries/language/l.php';
$this->l['hello'] = 'hello';
$this->l['helloworld'] = 'helloworld';
}
}
class Controller extends Framework
{
function index()
{
echo $this->l['hello'];
}
}
Well, that means for each Controller instance, you are going to keep a big array inside it.
Actually, you can make a singleton class that provides translation for text:
class Language
{
private static $instance;
public $l = array();
private function __construct() {
require 'libraries/language/l.php';
$this->l = $l;
}
public static function getInstance() {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
}
And you can have a shorthand function for it:
function l($text) {
return Language::getInstance()->l[$text];
}
And then use it:
echo l('hello') . "\n";
Please look at the following code snipped
class A
{
function __get($name)
{
if ($name == 'service') {
return new Proxy($this);
}
}
function render()
{
echo 'Rendering A class : ' . $this->service->get('title');
}
protected function resourceFile()
{
return 'A.res';
}
}
class B extends A
{
protected function resourceFile()
{
return 'B.res';
}
function render()
{
parent::render();
echo 'Rendering B class : ' . $this->service->get('title');
}
}
class Proxy
{
private $mSite = null;
public function __construct($site)
{
$this->mSite = $site;
}
public function get($key)
{
// problem here
}
}
// in the main script
$obj = new B();
$obj->render();
Question is: in method 'get' of class 'Proxy', how I extract the corresponding resource file name (resourceFile returns the name) by using only $mSite (object pointer)?
What about:
public function get($key)
{
$file = $this->mSite->resourceFile();
}
But this requires A::resourceFile() to be public otherwise you cannot access the method from outside the object scope - that's what access modifiers have been designed for.
EDIT:
OK - now I think I do understand, what you want to achieve. The following example should demonstrate the desired behavior:
class A
{
private function _method()
{
return 'A';
}
public function render()
{
echo $this->_method();
}
}
class B extends A
{
private function _method()
{
return 'B';
}
public function render()
{
parent::render();
echo $this->_method();
}
}
$b = new B();
$b->render(); // outputs AB
But if you ask me - I think you should think about your design as the solution seems somewhat hacky and hard to understand for someone looking at the code.