Change the class of an object at runtime - php

I'm working with a CMS, Joomla, and there's a core class which renders a set of parameters to a form, JParameter. Basically it has a render() function which outputs some table-laden HTML which is not consistent with the rest of my site.
For issues of maintainability, and because I have no idea where else this is being used, I don't want to change the core code. What would be ideal would to be able to define a new class which extends JParameter and then cast my $params object down to this new sub class.
// existing code --------------------
class JParameter {
function render() {
// return HTML with tables
}
// of course, there's a lot more functions here
}
// my magical class -----------------
class MyParameter extends JParameter {
function render() {
// return HTML which doesn't suck
}
}
// my code --------------------------
$this->params->render(); // returns tables
$this->params = (MyParameter) $this->params; // miracle occurs here?
$this->params->render(); // returns nice html

There's always PECL's Classkit but I get a feeling that you'd really rather not do this. Assuming you're directly calling $this->params->render(), you might just want to make a function/object that does an alternate rendering ( MyParamRenderer::render($this->params)) and avoid performing OO gymnastics not natively supported by the language.

What about creating a decorator of sorts that delegates anything apart from JParameter::render() to the existing object
class MyJParameter {
private $jparm;
function __construct( JParameter $jparm ) {
$this->jparm = $jparm;
}
function render() {
/* your code here */
}
function __get( $var ) {
if( isset( $this->$jparm->$var ) {
return $this->$jparm->$var;
}
return false;
}
function __set( $var, $val ) {
/* similar to __get */
}
function __call( $method, $arguments ) {
if( method_exists( $this->jparm, $method ) {
return call_user_func_array( array( $this->jparm, $method ), $arguments );
}
return false;
}
}
Or is this just too smelly?

Related

Extend PHP Class to allow new methods found via __callStatic

Looking for a flexible way to allow other developers to extend render methods for a templating system, basically allowing them to generate their own render::whatever([ 'params' ]) methods.
Current set-up work well from a single developer point of view, I have a number of classes set-up based on context ( post, media, taxonomy etc ), with a __callStatic method collecting the calling function which checks if the method_exists within the class, and if so, extracts any passed arguments and renders the output.
quick example ( pseudo-code ):
-- view/page.php
render::title('<div>{{ title }}</div>');
-- app/render.php
class render {
public static function __callStatic( $function, $args ) {
// check if method exists
if ( method_exists( __CLASS__, $function ){
self::{ $function }( $args );
}
}
public static function title( $args ) {
// do something with the passed args...
}
}
I want to allow developers to extend the available methods from their own included class - so they could create for example render::date( $args ); and pass this to their logic to gather data, before rendering the results to the template.
The questions is, what approach would work best and be performant - errors are safety are not a big concern at this point, that can come later.
EDIT --
I am already making this work by doing the following ( pseudo-code again.. ):
-- app/render.php
class render {
public static function __callStatic( $function, $args ) {
// check if method exists
if (
method_exists( __CLASS__, $function
){
self::{ $function }( $args );
}
// check if method exists in extended class
if (
method_exists( __CLASS__.'_extend', $function
){
__CLASS__.'_extend'::{ $function }( $args );
}
}
public static function title( $args ) {
// do something with the passed args...
}
}
-- child_app/render_extend.php
class render_extend {
public static function date( $args = null ) {
// do some dating..
}
}
The issue here is that this is limited to one extension of the base render() class.
A common way (used by Twig and Smarty, for a couple of examples), is to require developers to manually register their extensions as callables. The render class keeps a record of them, and then as well as checking its own internal methods, also checks this list from _callStatic.
Based on what you have already, this might look like this:
class render
{
/** #var array */
private static $extensions;
public static function __callStatic($function, $args)
{
// check if method exists in class methods...
if ( method_exists( __CLASS__, $function )) {
self::{$function}(self::$args);
}
// and also in registry
elseif (isset(self::$extensions[$function])) {
(self::$extensions[$function])($args);
}
}
public static function title($args)
{
// do something with the passed args...
}
public static function register(string $name, callable $callback)
{
self::$extensions[$name] = $callback;
}
}
A developer would make use of this like so:
render::register('date', function($args) {
// Do something to do with dates
});
Full demo here: https://3v4l.org/oOiN6

How to use reusable validation in a ValueObject

I'm trying to get my head around combining some techniques.
It seems good practice to never make it possible to create a ValueObject that is not valid. The ValueObject constructor therefor should fail whenever the provided content is not good enough to create a valid ValueObject. In the examples I have, an EmailAddress object can only be created when there is a value present. So far, so good.
Validating the value of the provided emailaddress, that's where I begin to doubt the principles. I have four examples, but I can't tell which one should be considered the best practice.
Example 1 is the easy one: simply a construct function, a required parameter "value", and a separate function validate to keep the code clean. All the validation code stays inside the class, and will never be available to the outside world. The class has only one purpose: store the emailaddress, and make sure it will never be an invalid one. But the code will never be reusable - I create an object with it, but that's all.
public function __construct ($value)
{
if ( $this->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
protected function validate ($value)
{
return is_string($value); // Wrong function, just an example
}
Example 2 makes the validate function a static function. The function will never change the state of the class, so it is a correct use of the static keyword, and the code in it will never be able to change anything to any instance created from the class embedding the static function. But if I want to reuse the code, I can call the static function. Still, this feels dirty to me.
public function __construct ($value)
{
if ( $self::validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
public static function validate ($value)
{
return is_string($value); // Wrong function, just an example
}
Example 3 introduces another class, hardcoded inside the body of my object. The other class is a validation class, containing the validation code, and creates thus a class that can be used whenever and wherever I need a validation class. The class itself is hardcoded, which also means that I create a dependency on that validation class, which should be always nearby, and is not injected through dependency injection. One could say that having a validator hard coded is as bad as having the complete code embedded in the object, but on the other hand: DI is important, and this way one has to create a new class (extending, or simply rewriting) to simply change the dependency.
public function __construct ($value)
{
if ( $this->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
protected function validate ($value)
{
$validator = new \Validator();
return $validator->validate($value);
}
Example 4 uses the validator class again, but puts it in the constructor. My ValueObject thus needs a validator class already present and created, before creating the class, but it is possible to easily overwrite the validator. But how good is it for a simple ValueObject class to have such a dependency in the constructor, as the only thing really important is the value, it should not be my concern to know how and where to handle if the email is correct, and providing a correct validator.
public function __construct ($value, \Validator $validator)
{
if ( $validator->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
The last example I started thinking about, is providing a default validator, and meanwhile make it possible to inject through DI an overwrite for the validator in the constructor. But I started doubting how good a simple ValueObject is when you overwrite the most important part: the validation.
So, anyone has an answer which way one should best write this class, that is correct for something as easy as an emailaddress, or something more complex like a barcode or a visa card or whatever one may think about, and doesn't violate DDD, DI, OOP, DRY, wrong use of static, and so on...
The complete code:
class EmailAddress implements \ValueObject
{
protected $value = null;
// --- --- --- Example 1
public function __construct ($value)
{
if ( $this->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
protected function validate ($value)
{
return is_string($value); // Wrong function, just an example
}
// --- --- --- Example 2
public function __construct ($value)
{
if ( $self::validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
public static function validate ($value)
{
return is_string($value); // Wrong function, just an example
}
// --- --- --- Example 3
public function __construct ($value)
{
if ( $this->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
protected function validate ($value)
{
$validator = new \Validator();
return $validator->validate($value);
}
// --- --- --- Example 4
public function __construct ($value, \Validator $validator)
{
if ( $validator->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
}
Example 4!
Why? Because it's testable, plain and simple.
Depending on what your validator actually does (in some circumstances your validator may rely on an API call or a call to a database) the injectable validator is completely testable via mocks. All of the other's are either impossible to test under the circumstances I just mentioned, or incredibly hard to test.
EDIT: For those wondering how the dependency injection method helps with testing then consider the CommentValidator class below that utilises a standard Akismet spam checking library.
class CommentValidator {
public function checkLength($text) {
// check for text greater than 140 chars
return (isset($text{140})) ? false : true;
}
public function checkSpam($author, $email, $text, $link) {
// Load array with comment data.
$comment = array(
'author' => $author,
'email' => $email,
'website' => 'http://www.example.com/',
'body' => $text,
'permalink' => $link
);
// Instantiate an instance of the class.
$akismet = new Akismet('http://www.your-domain.com/', 'API_KEY', $comment);
// Test for errors.
if($akismet->errorsExist()) { // Returns true if any errors exist.
if($akismet->isError('AKISMET_INVALID_KEY')) {
return true;
} elseif($akismet->isError('AKISMET_RESPONSE_FAILED')) {
return true;
} elseif($akismet->isError('AKISMET_SERVER_NOT_FOUND')) {
return true;
}
} else {
// No errors, check for spam.
if ($akismet->isSpam()) {
return true;
} else {
return false;
}
}
}
}
And now below, when you're setting up your unit tests we have a CommentValidatorMock class that we use instead, we have setters to manually change the 2 output bools we can have, and we have the 2 functions from above mock'd up to output whatever we want without having to go through the Akismet API.
class CommentValidatorMock {
public $lengthReturn = true;
public $spamReturn = false;
public function checkLength($text) {
return $this->lengthReturn;
}
public function checkSpam($author, $email, $text, $link) {
return $this->spamReturn;
}
public function setSpamReturn($val) {
$this->spamReturn = $val;
}
public function setLengthReturn($val) {
$this->lengthReturn = $val;
}
}
If you're serious about unit testing then you need to use DI.
The first instinct is usually the best. You should use the first option. EmailAddress is a value object. It can be reused in other value objects or entities. I don't understand why you think it's not reusable. You can have a "shared library" of these common value objects used in other bounded contexts. Just be careful what you put in there. They would need to be truly generic if that's even conceptually possible.
I think if you use separate validation methods or move the validators to separate class will be butter and prevent DRY
class EmailAddress{
protected $value;
public function __construct ($value)
{
$this->value = \validateEmailAddress($value);
}
}
function validateEmailaddress(string $value) : string
{
if(!is_string($value)){
throw new \ValidationException('This is not an emailaddress.');
} // Wrong function, just an example
return $value;
}
//OR for strict OOP people
final class VOValidator{
private function __construct(){}
public static function validateEmailaddress(string $input): string{...}
}
//I will prefer even go far and use Either from (FP monads)
interface ValueObejctError {}
class InvalidEmail implements ValueObjectError {}
function validateEmailaddress(string $input): Either {
// it will be better if php supported generic so using Either<InvalidaEmail, string> is more readable but unfortunately php has no generic types, maybe in future
return is_string($input)
? new Right($input)
: new Left(new InvalidEmail());
}

How to implement flag for execution of abstract PHP method?

I have part of abstract base class that looks like this:
abstract class Fragment_Cache {
static $in_callback = false;
abstract public function callback( $name, $args );
}
I need to flip $in_callback to true during callback() method execution. That is used in other part of code to prevent nesting of caches (so I want to cache widget and menu, but not menu inside widget).
However since it is abstract method I cannot rely on subclass implementations for that.
I also cannot flip flag on/off around method call, because it is passed on and executed by different library that takes care of running it async instead of during page load.
How can I architecture myself out of this corner? :)
Actual monstrosity that sets up its call:
$output = tlc_transient( 'fragment-cache-' . $this->type . '-' . $name . $salt )
->updates_with( array( $this, 'callback' ), array( $name, $args ) )
->expires_in( $this->timeout )->get();
How about hiding the actual functionality in another function?
abstract class Fragment_Cache {
static $in_callback = false;
public function callback($name, $args)
{
self::$in_callback = true;
$this->doCallback($name, $args);
self::$in_callback = false;
}
abstract protected function doCallback( $name, $args );
}
You need to overwrite doCallback, which will do the actual heavy-lifting, but is not accessible directly from the outside, only via callback.
abstract class Fragment_Cache {
static $in_callback = false;
public function callback( $name, $args ){
self::$in_callback = true;
$ret = $this->__doCallback($name, $args);
self::$in_callback = false;
return $ret;
}
abstract protected function __doCallback($name, $args);
}

Lost access to same property trying to use best practice / design pattern

I had:
in a class implementing Validator:
an $errormessages property
an isCorrect() method
In the isCorrect method, I had:
switch ($type):
case 'email':
isEmailCorrect();
case 'password':
isPasswordCorrect();
case 'x':
isXCorrect();
isEmailCorrect(), isPasswordCorrect() and isXCorrect() had access to the same property with all error messages
Now, I have:
in Validator:
an $errormessages property
in an EmailValidator class extending Validator:
an isCorrect() method
in a PasswordValidator class extending Validator:
an isCorrect() method
in a XValidator class extending Validator:
an isCorrect() method
Now, in a file calling the isCorrect() methods, I have:
$EmailValidator = new EmailValidator();
$PasswordValidator = new PasswordValidator();
$XValidator = new XValidator();
$EmailValidator->isCorrect(), $PasswordValidator->isCorrect() and $XValidator->isCorrect() don't have access to the same property with all error messages
$errormessages are in different instances of different classes. They should be one, but are three.
What now?
I think you should develop another class: a ValidatorChain, which takes an arbitrary amount of validators, and that aggregates the errormessages of all validators that it has tested
For reference see the docs on Zend Framework's Validator Chain
EDIT
Now that I re-evaluate your question (thanks to Bryan M's comment); why do you want each individual Validator to have access to other Validators' error messages? I would say that collecting each individual Validators' error messages is the responsibility of an object higher in the hierarchy.
If, however, you want individual Validators to be able to act based on context, in other words, based on what the results of other Validators are, then I suppose you could add a $context parameter to the isCorrect method. This could for instance accept an arbitrary amount of Validators or something similar.
Something like:
interface ValidatorInterface
{
public function isCorrect( array $context );
public function getMessages();
}
abstract class ValidatorContextOptions
{
const SHOULD_BE_PRESENT = 'shouldBePresent';
const SHOULD_NOT_BE_PRESENT = 'shouldNotBePresent';
const SHOULD_BE_VALID = 'shouldBeValid';
}
class EmailValidator implements ValidatorInterface
{
protected $_field;
protected $_contextOptions = array();
protected $_messages = array();
public function __construct( $field, array $contextOptions )
{
$this->_field = $field;
$this->_contextOptions = $contextOptions;
}
public function isCorrect( array $context = null )
{
foreach( $this->_contextOptions as $field => $options )
{
foreach( $options as $option )
{
switch( $option )
{
case ValidatorContextOptions::SHOULD_NOT_BE_PRESENT:
if( isset( $context[ $field ] )
&& $context[ $field ] instanceof ValidatorInterface )
{
$this->_messages[] = $field . ' should not be present';
return false;
}
break;
case ValidatorContextOptions::SHOULD_BE_PRESENT:
if( !isset( $context[ $field ] )
|| !$context[ $field ] instanceof ValidatorInterface )
{
$this->_messages[] = $field . ' should be present';
return false;
}
break;
case ValidatorContextOptions::SHOULD_BE_VALID:
if( !isset( $context[ $field ] )
|| !$context[ $field ] instanceof ValidatorInterface
|| !$context[ $field ]->isCorrect() )
{
$this->_messages[] = $field . ' should be valid';
return false;
}
break;
}
}
}
// some dummy function which you should replace with real validation
return isAnEmailAddress( $this->_field );
}
public function getMessages()
{
return $this->_messages;
}
}
Usage:
$emailValidatorContextOptions = array
(
'phone' => array(
ValidatorContextOptions::SHOULD_BE_PRESENT,
ValidatorContextOptions::SHOULD_BE_VALID
)
);
$phoneValidator = new PhoneValidator( $phoneString );
$emailValidator = new EmailValidator( $emailString, $emailValidatorContextOptions );
if( !$emailValidator->isCorrect( array( 'phone' => $phoneValidator ) ) )
{
print_r( $emailValidator->getMessages() );
}
What I've shown here, needs a lot more thinking (and I really mean A LOT), is buggy as hell and definately not bulletproof. But I hope you catch my drift of where I'm going with this.
Moreover, where do you insert the values in your validator that need to be validated anyway?
Well you could make an external properties factory to control access to your property, assuming you are talking about properties files that is the approach I usually take.
If you are referring to a shared field then you can place it in your base class and access it that way.
I'll often use Zend_Validate classes to perform the validation, and aggregate any error message to a property on the object that's being validated (as well as a flag that control valid status).
My setup would be similar to this:
class User {
public $email;
protected $_errorMessages = array();
public function validate()
{
$valid = true;
$emailValidator = new EmailValidator();
if (!$emailValidator->isCorrect($this->email)) {
$valid = false;
// validation message are added to the $errormessages property in
// the validator class upon failure of isCorrect()
$this->_errorMessages[] = $emailValidator->getMessages();
}
// repeat this for all your validators
return $valid
}
public function getErrorMessages()
{
return $this->_errorMessages();
}
}
// in your page....
if (!$user->validate()) {
$messages = $user->getErrorMessages();
}
If I read you right, you want multiple instances to share the same error messages property, such that you can instantiate several validators and have them all contribute to a single array.
If this is the case, there are a few ways to do it. One would be to create a validator manager class which has responsibility for instantiating and registering validators. Then once validation is complete you could call $validator_manager->getErrors() which would aggregate the errors present in all the validators registered with it.
Another way you could do it would be to use a singleton error store class, which you acquire in the constructor of each validator. Each validator's addError() method would then delegate the job to the singleton.
There are other methods still, but basically you're going to have to use another object, either for managing the validators or storing the errors.
Someone below mentioned using a singleton for this.
I am not convinced that it's a great use of that design pattern, especially since it's commonly held that singletons are the "anti-pattern" and often over/mis-used.
Nonetheless, keeping that in mind, here's an example along those lines:
<?php
//Error Class implemented as a Singleton
class ErrorClass
{
static private $instance = false;
static private $errorMessages;
function getInstance() {
if (!self::$instance) {
self::$instance = new ErrorClass();
self::$errorMessages = "No errors;";
}
return self::$instance;
}
public function setError($errorMessage){
self::$instance->errorMessages .= $errorMessage;
}
public function getError(){
return self::$instance->errorMessages;
}
}
abstract class AbstractClass
{
// Force Extending class to define this method
abstract protected function isCorrect($b);
// Common Method for setting error
public function setError($errorMessage) {
ErrorClass::getInstance()->setError($errorMessage);
}
// Common Method for getting error
public function getError() {
return ErrorClass::getInstance()->getError();
}
}
class EmailValidator extends AbstractClass
{
public function isCorrect($b) {
if(!$b) {
$this->setError('EmailValidator->isCorrect();');
}
}
}
class PasswordValidator extends AbstractClass
{
public function isCorrect($b) {
if(!$b) {
$this->setError('PasswordValidator->isCorrect();');
}
}
}
// Then in your code
$errorState = 1; // used for testing purposes
$EmailValidator = new EmailValidator();
$EmailValidator->isCorrect($errorState);
$PasswordValidator = new PasswordValidator();
$PasswordValidator->isCorrect($errorState);
echo $EmailValidator->getError();
echo $PasswordValidator->getError();

unit testing datastores in PHP

I'm using PHPUnit but find it difficult to make it create good mocks and stubs for objects used as datastore.
Example:
class urlDisplayer {
private $storage;
public function __construct(IUrlStorage $storage) { $this->storage = $storage; }
public function displayUrl($name) {}
public function displayLatestUrls($count) {}
}
interface IUrlStorage {
public function addUrl($name, $url);
public function getUrl($name);
}
class MysqlUrlStorage implements IUrlStorage {
// saves and retrieves from database
}
class NonPersistentStorage implements IUrlStorage {
// just stores for this request
}
Eg how to have PHPUnit stubs returning more than one possible value on two calls with different $names?
Edit: example test:
public function testUrlDisplayerDisplaysLatestUrls {
// get mock storage and have it return latest x urls so I can test whether
// UrlDisplayer really shows the latest x
}
In this test the mock should return a number of urls, however in the documentation I only how to return one value.
Your question is not very clear - but I assume you are asking how to use phpunit's mock objects to return a different value in different situations?
PHPUnit's mock classes allow you specify a custom function (ie: a callback function/method) - which is practically unlimited in what it can do.
In the below example, I created a mock IUrlStorage class that will return the next url in its storage each time it is called.
public function setUp()
{
parent::setUp();
$this->fixture = new UrlDisplayer(); //change this to however you create your object
//Create a list of expected URLs for testing across all test cases
$this->expectedUrls = array(
'key1' => 'http://www.example.com/url1/'
, 'key2' => 'http://www.example.net/url2/'
, 'key3' => 'http://www.example.com/url3/'
);
}
public function testUrlDisplayerDisplaysLatestUrls {
//Init
$mockStorage = $this->getMock('IUrlStorage');
$mockStorage->expects($this->any())
->method('getUrl')
->will( $this->returnCallback(array($this, 'mockgetUrl')) );
reset($this->expectedUrls); //reset array before testing
//Actual Tests
$this->assertGreaterThan(0, count($this->expectedUrls));
foreach ( $this->expectedUrls as $key => $expected ) {
$actual = $this->fixture->displayUrl($key);
$this->assertEquals($expected, $actual);
}
}
public function mockGetUrl($name)
{
$value = current($this->expectedUrls);
next($this->expectedUrls);
//Return null instead of false when end of array is reached
return ($value === false) ? null : $value;
}
Alternatively, sometimes it is easier to simply create a real class that mocks up the necessary functionality. This is especially easy with well defined and small interfaces.
In this specific case, I would suggest using the below class instead:
class MockStorage implements IUrlStorage
{
protected $urls = array();
public function addUrl($name, $url)
{
$this->urls[$name] = $url;
}
public function getUrl($name)
{
if ( isset($this->urls[$name]) ) {
return $this->urls[$name];
}
return null;
}
}
?>
Then in your unit test class you simply instantiate your fixture like below:
public function setUp() {
$mockStorage = new MockStorage();
//Add as many expected URLs you want to test for
$mockStorage->addUrl('name1', 'http://example.com');
//etc...
$this->fixture = new UrlDisplayer($mockStorage);
}

Categories