Ideally I would like to do something like this....
$formElement->addValidator
(
(new RegexValidator('/[a-z]/') )->setErrorMessage('Error')
// setErrorMessage() returns $this
);
Of course PHP won't allow that, so I settle for this...
$formElement->addValidator
(
RegexValidator::create('/[a-z]/')->setErrorMessage('Error')
);
And the code in the Base class....
static public function create( $value )
{
return new static( $value );
}
I would like to go one step further and do something like this...
static public function create()
{
return call_user_func_array( 'static::__construct', func_get_args() );
}
Again, PHP won't allow me to do this. I could code individual 'create' methods for each validator, but I want it to be a little more slick.
Any suggestions please?
Corzin massively pointed me in the right direction, Reflection - (thanks Krzysztof).
Please note that late static binding applies, which is only a feature of PHP >= 5.3
The method of interest is Validator::create(). It provides a work-around for the lack of ability to call methods on objects which have bee created inline (see my original question).
The base class...
class Validator
{
....
static public function create()
{
$class = new ReflectionClass( get_called_class() );
return $class->newInstanceArgs( func_get_args() );
}
public function setErrorMessage( $message )
{
....
}
The extended class....
class RegexValidator extends Validator
{
public function __construct( $regex )
{
....
}
A usage example...
$form
->getElement('slug')
->setLabel( 'Slug' )
->addValidator( RegexValidator::create('/[a-z]/')->setErrorMessage('Error') )
->addValidator( RequiredValidator::create() );
Use ReflectionClass::newInstanceArgs from Reflection API:
$class = new ReflectionClass(__CLASS__);
return $class->newInstanceArgs($args);
Related
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
I have the following code, perform a global function within a class to fill the functions of wordpress, the problem is that the only way that I could get a variable public class is as follows
class Core {
public $notice;
function __construct(){
$this->core_function();
}
function core_function(){
global $globalvar;
$globalvar = $this;
function notice_global(){
global $globalvar;
return $globalvar->notice;
}
}
function set_notice(){
$this->notice = array('Warning');
}
}
$GP = new Core();
$GP->set_notice();
var_dump(notice_global());
Any other ideas or suggestions, this code is correct or not?
As you said in the comments, you need global function due to wordpress hook method (for a plugin, I suppose).
This is not necessary: there is a way to pass an object method (not a whole object) to wordpress.
You can try in this way:
class Core {
public $notice;
function get_notice()
{ return $this->notice; }
function set_notice()
{ $this->notice = array('Warning'); }
}
$GP = new Core();
$GP->set_notice();
add_action( 'save_post', array( $GP, 'get_notice' ) );
Or - for a better flexibility - in this way:
class Core {
public $notice;
function get_notice()
{ return $this->notice; }
function set_notice()
{ $this->notice = array('Warning'); }
function add_wp_action( $hook, $method )
{ add_action( $hook, array( $this, $method ) ); }
}
$GP = new Core();
$GP->set_notice();
$GP->add_wp_action( 'save_post', 'get_notice' );
By this way, you can directly set all your wp hooks in the class and call they directly with an object method, without using globals variables or function tricks.
I'm not sure if I'm understanding you right, but notice_global can be moved out of that class.
Globals have scope outside of classes
There is no need for these functions. You've defined $notice as public property. You can access it like this: $GP->notice;
You might also want to read documentation on visibility of methods and properties.
I'm working on a plugin system for my CMS, to make the event registering system easy I need a function that can do the following.
I need to have a function that will return all functions from a specified class with the classes of their parameters. Of course, it's fine if the function to get the functions from a class and the function to get all the class names of the parameters of a function are different.
For example if you have the following class with these functions;
class MyClass {
public function myFunction(Event $event) {
// Function code
}
}
It would be awesome if something like this could be returned;
Array() {
'myFunction' => Array() {
0 => 'Event'
}
}
Is there a way to do this?
Thanks in advance,
Tim Visée
You are exactly referring to the Reflection API. Reflecting classes or methods could lead you to do what you need. For example, try that:
$class = new ReflectionClass('MyClass');
$methods = $class->getMethods();
print_r($methods);
foreach ($methods as $method) {
print_r($method->getParameters());
}
we have a problem [cit.]
I need to assign a callback dynamically within a class, in base of a variable param: my goal is to have just one class (and not a main class and many extender sub-class), and inside this class if a value is X, then the funcitonX must be used, if is Y, the functionY.
I know i cant explain well, i hope my example will do:
class plzComplicateMyLife{
public $vehicle;
public $kindVehicle;
public $dynamicFunction;
public function __construct($vehicle, $kindVehicle){
$this->kindVehicle = $kindVehicle;
$this->vehicle = $vehicle;
switch($kindVehicle){
case 'cycle':
$this->dynamicFunction = "isACycle";
break;
case 'car':
$this->dynamicFunction = "isACar";
break;
}
//here come the problem, i need to call the callback store in dynamicFunction.
//i tried:
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//error: Catchable fatal error: Object of class plzComplicateMyLife could not be converted to string in [...]
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//Warning: call_user_func(plzComplicateMyLife::isACar) [function.call-user-func]: First argument is expected to be a valid callback in [...]
//$this->dynamicFunction();
//Fatal error: Call to undefined method plzComplicateMyLife::dynamicFunction() in [...]
//so, how can i do that?
}
public function isACycle($vehicle){
echo 'im a cycle, model: '.$vehicle.'<br />';
}
public function isACar($vehicle){
echo 'im a car, model: '.$vehicle.'<br />';
}
//i know this has no sense, in this example at least.
public function printKind(){
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//then?
}
}
$maserati = new plzComplicateMyLife('maserati4', 'car');
//then, maybe, outside the class i'll need to recover the callback:
$maserati->printKind();
EDIT:
As Rob said, polymorphism would be really a good solution.
But the problem is that, in this case, i really must have the same declaration for every class instance, changing only the parameters...e.g:
$maserati = new plzComplicateMyLife('maserati4', 'car');
$ducati = new plzComplicateMyLife('maserati4', 'cycle');
//is good
//becose i cant have:
$maserati = new plzComplicateMyLifeWithACar('maserati4');
$ducati = new plzComplicateMyLifeWithACycle('maserati4');
Polymorphism is the way to go here but for future reference you can also do this:
public function printKind() {
$this->{$this->dynamicFunction}($this->vehicle);
}
In response to your edit, could you not do something like this instead?
abstract class MethodOfTransport {
protected $model;
public function __construct($model) {
$this->model = $model;
}
abstract public function printKind();
public static function create($model, $type) {
$object = new $type($model);
return $object;
}
}
class cycle extends MethodOfTransport {
public function printKind() {
echo 'im a cycle, model: '.$this->model.'<br />';
}
}
class car extends MethodOfTransport {
public function printKind() {
echo 'im a car, model: '.$this->model.'<br />';
}
}
$maserati = MethodOfTransport::create('maserati4', 'car');
$maserati->printKind();
$ducati = MethodOfTransport::create('maserati4', 'cycle');
$ducati->printKind();
In PHP you can use specify a method callback using an array as a callback variable (see here), for example:
array( $object, $methodName );
So you could do this
$callback = array($this, $this->dynamicFunction);
call_user_func($callback, $this->vehicle);
Er, why don't you want to use a simple inheritance structure here? If you want different behaviour depending upon the object modelled, then that's pretty much the canonical description of polymorphism.
If you really do want to plough on with callbacks into the same object, then you'll need to do one of two things:
Drop the $vehicle parameter from your callbacks, make them private or protected, and call into them normally, i.e.
call_user_func( array( $this, 'isACycle' ) );
Mark the callback as static, make them private or protected, and call into them as follows:
call_user_func( array( __CLASS__, 'isACycle' ), $this );
Within the non-static callback, access the object's properties via $this in the normal fashion. Note also that I suggest marking the callback as private or protected, in order to prevent unnecessary outside callers; presumably, you don't want them executing the wrong method for each type.
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?