I have a problem, I cannot call a function before all functions.
I have a parent class - that is a repository.
class Repository {
public function find(/*..*/){/*..*/}
public function findAll(/*..*/){/*..*/}
public function findBy(/*..*/){/*..*/}
public function findA(/*..*/){/*..*/}
public function findB(/*..*/){/*..*/}
/* then 100+ more public function */
}
And I want to create an "Adapter class" that will be calling a function that run before all only public functions BUT I don't want "overwriting" all functions of the parent.
I tried this solution:
class OwnRepo extends Repository{
public __call($methods, $args){/**/}
}
BUT the __call method not working with public methods
How can I solve this problem?
Thank you!
** UPDATE **
Sorry I was not clear!
My controller implements a model, I don't want to change/rewrite the functions of the controllers.
class IndexController {
public function index(){
$model = new Model(); // will return a OwnRepo object
$a = model->findAll();
}
}
In my opinion you can't do this with inheritance. You have to check if the desired method exists in the Repository class and then call it.
Try this one:
class Repository
{
public function find($a,$b,$c)
{
return "find $a $b $c";
}
}
class OwnRepo
{
function __call($name, $arguments)
{
if (method_exists('Repository', $name)) {
//some action before
$repo = new Repository();
$result = call_user_func_array(array($repo, $name), $arguments);
//some action afterwards
return $result;
} else {
die("Method " . $name . " does not exist");
}
}
}
$o = new OwnRepo();
echo $o->find(1,2,3);
Related
The magical __call() and __callStatic can pretty much handle any non existing method on the class, but is there a way to handle a non existing magical method on a class?!
Here's an example on why I need this:
I have a class called DoSomething:
class DoSomething{
public function ok(){
echo 'Something!';
}
}
I want to call this class as a function for a reason! which should call the __invoke function of that class:
$doSomething = new DoSomething();
$doSomething();
Normally by doing that, the class should look for the __invoke function, however in my case I don't to have that function declared on my class (DoSomething), instead I want to be able to call another function (such as the ok()) if the __invoke doesn't exist.
I was expecting something like this to work, but of course it didn't :)
public function __call($class, $arguments)
{
$object = IoC::resolve($class);
$object->ok(...$arguments);
}
The main goal is to use the class as a function, without having to declare the __invoke method. Handle the function does not exist error and call another function instead.
I think that would be really cool :D I appreciate suggestions or other solutions to achieve this.
Internal solution
Extract an abstract class
You could extract an abstract class and have your classes extend it:
<?php
abstract class Invokable
{
public function __invoke()
{
return $this->ok();
}
abstract public function ok();
}
class DoSomething extends Invokable
{
public function ok()
{
echo 'Something';
}
}
$doSomething = new DoSomething();
echo $doSomething();
For an example, see:
https://3v4l.org/m0ih8
Extract a trait
You could extract a trait and have your classes use it:
<?php
trait InvokableTrait
{
public function __invoke()
{
return $this->ok();
}
}
class DoSomething
{
use InvokableTrait;
public function ok()
{
echo 'Something';
}
}
$doSomething = new DoSomething();
echo $doSomething();
For an example, see:
https://3v4l.org/ftUfI
External Solution
Create a proxy
You could create a proxy (a decorator) that composes the object that is not invokable:
<?php
class InvokableDecorator
{
private $decorated;
public function __construct($decorated)
{
$this->decorated = $decorated;
}
public function __call($name, $arguments)
{
/**
* delegate to decorated object if the method exists
*/
if (method_exists($this->decorated, $name)) {
return $this->decorated->{$name}($arguments);
}
}
public function __invoke()
{
return $this->decorated->ok();
}
}
class DoSomething
{
public function ok()
{
echo 'Something';
}
}
$doSomething = new InvokableDecorator(new DoSomething());
echo $doSomething();
For an example, see:
https://3v4l.org/C3XEX
Create a handler
You could create a handler that takes care of determining this externally:
<?php
class Handler
{
public function handle($subject)
{
if (is_callable($subject)) {
return $subject();
}
if (method_exists($subject, 'ok')) {
return $subject->ok();
}
throw new \BadMethodCallException(sprintf(
'Unable to handle instance of "%s"',
get_class($subject)
));
}
}
class DoSomething
{
public function ok()
{
echo 'Something';
}
}
$handler = new Handler();
echo $handler->handle(new DoSomething());
For an example, see:
https://3v4l.org/E0NVs
I have a PHP library which I don't want to edit, and implement to my code by extending/overriding some methods. But I'm stuck with chainability. For example:
class MomentPHP extends Moment {
public $uniqueSettings;
public function formatJS(){
return parent::format($this->uniqueSettings);
}
}
class Moment {
public function startOf(){
//some code
return $this;
}
}
I want to do this:
$momentphp = new MomentPHP();
$dateStart = $momentphp->startof('month')->formatJs();
And the way to do this is overriding all the methods in the child class inside MomentPHP to return itself.
Is there any other simple way to do this? like using _call or something?
Edit: Found one way to do this:
Remove the inheritance,
Create a instance variable of parent class,
use __call method to switch between classes.
Like this:
class MomentPHP {
private $instance = null;
public $uniqueSettings;
public function __construct(){
$this->instance = new Moment();
}
public function __call($method,$args){
if(in_array($method, get_class_methods($this))){
call_user_func(array($this,$method),$args);
else
call_user_func(array($this->instance,$method),$args);
return $this;
}
public function formatJS(){
return $this->instance->format($this->uniqueSettings);
}
}
class Moment {
public function startOf(){
//some code
return $this;
}
}
Is there any better way?
One proper way to do this is:
class MomentPHP {
private $instance = null;
public $uniqueSettings;
public function __construct(){
$this->instance = new Moment();
// settings etc.
}
public function __call($method,$args){
$result = NULL;
if(in_array($method, get_class_methods($this))){
$result = call_user_func(array($this,$method),$args);
else
$result = call_user_func(array($this->instance,$method),$args);
if($result instanceof Moment)
$this->instance = $result;
return $this;
}
public function format(){
return $this->instance->format($this->uniqueSettings);
}
}
Updating the instance from the method result is the key operation, and using $this instead of $this->instance allows you to use the extender class in every call. So you can override the function while using other methods in the parent class with chaining ability.
I have a hard time figuring out how to add a variable value to an instantiated class in php,
I've been looking at the reflectionClass and tried to return an assigned variable, and now I'm ended up with a getter setter.
I would really appreciate some help, here's an example of my code:
class controller
{
public $models;
private $load;
public function __construct()
{
$this->load = new loader();
}
public function action_being_run()
{
$this->load->set_model('model_name');
}
}
class loader
{
public function set_model($name)
{
{controller_class}->models[$name] = new model();
}
}
The controller class is instantiated without assigning it to a variable, but just:
new controller();
And then the action is executed from within the controller class.
You could pass a reference to $this into set_model()
class controller
{
public $models;
private $load;
public function __construct()
{
$this->load = new loader();
}
public function action_being_run()
{
$this->load->set_model('model_name', $this);
}
}
class loader
{
public function set_model($name, &$this)
{
{controller_class}->models[$name] = new model();
}
}
You also need to change public $model to public $models. There are probably other ways to achieve what you want, by either extending a class or just using magic methods to access the model.
Like this:
class tester{
public function lame(){
return 'super lame';
}
}
function after(){
return 'after function';
}
$tst = new tester; $tst->afterVar = 'anything'; $tst->afterFun = 'after';
echo $wh->afterVar;
echo $wh->afterFun();
Given class A that extends class B, how can I have calls to class A's __call function override the matching function inherited from the parent?
Consider this simplified example:
class A
{
public function method_one()
{
echo "Method one!\n";
}
}
class B extends A
{
public function __call($name, $args)
{
echo "You called $name!\n";
}
}
$b = new B();
$b->method_one();
When I run it, I get the output Method one!. I WANT to get the output You called method_one!.
So, how do I have the subclass's magic method override the parent classes defined method?
I need to extend the object, because I need access to a protected method in A, but I want to channel all public methods into my own __call handler. Is there any way to do this?
So, I found a way to do it, which involves making an intermediate class to expose the protected method I need, while still using __call for the public ones. This works, but I really don't like the idea of extending a class just to expose a protected method... Still, someone might find it useful, so thought I'd share:
class A
{
public function method_one()
{
echo "Method one!\n";
}
protected function protected_method()
{
echo "Accessible!\n";
}
}
class A_accessor extends A
{
public function publicise()
{
$args = func_get_args();
return call_user_func_array(array($this, array_shift($args)), $args);
}
}
class B
{
private $A;
public function __construct()
{
$this->A = new A_accessor();
}
public function __call($name, $args)
{
echo "You called $name!\n";
}
public function protected_method()
{
return $this->A->publicise('protected_method');
}
}
$b = new B();
$b->method_one();
$b->protected_method();
This is the answer I actually used, based on Mark Baker's comment.
By having an object of the class whose methods I want access to as a variable, I can use ReflectionMethod to access any of its methods just as if I was extending it, but with __call still catching everything else. So any methods I want to pass through, I can pass through with something like this:
public function __call($name, $args)
{
$method = new ReflectionMethod($this->A, $name);
$method->setAccessible(true);
return $method->invokeArgs($this->A, $args);
}
Or in my case, with the full class like this:
class B
{
private $A;
public function __construct()
{
$this->A = new A();
}
public function __call($name, $args)
{
echo "You called $name!\n";
}
public function protected_method()
{
$method = new ReflectionMethod($this->A, 'protected_method');
$method->setAccessible(true);
return $method->invoke($this->A, $args);
}
}
try this
class A1
{
protected function method_one()
{
echo "Method one!\n";
}
}
class B1
{
private $A;
public function __construct()
{
$this->A = new A1;
}
public function __call($name, $args)
{
$class = new ReflectionClass($this->A);
$method = $class->getMethod($name);
$method->setAccessible(true);
//return $method;
echo "You called $name!\n";
$Output=$method->invokeArgs($this->A, $args);
$method->setAccessible(false);
return $Output;
}
}
$a = new B1;
$a->method_one("");
I have a big problem. How to get called subclass method from a superclass. Please execute below code.
class Model {
public function render(){
echo '<br />class: '.get_class($this).' -- function: '.__FUNCTION__;
}
}
class Product extends Model {
public function show(){
$this->render();
}
}
class User extends Model {
public function index(){
$this->render();
}
}
$p = new Product();
$u = new User();
echo $p->show();
echo $u->index();
result :
class: Product -- function: render
class: User -- function: render
How to get subclass method name instead of render?
Thanks.
You can get that information using debug_backtrace().
I am curious as to why you want this - it could indicate a flaw with your design if you need this for anything other than debugging.
The __FUNCTION__ thingie is replaced at compile-time by the name of the function it is in. So no matter how your object model is structured, you'll get the function where __FUNCTION__ is met by PHP's preprocessor.
The best you can do here, if you want to know the name of the method being called, is to add it as a parameter to the method render() :
class Model {
public function render($methodName){
echo '<br />class: '.get_class($this).' -- function: '. $methodName;
}
}
And add the name in the method calls :
class Product extends Model {
public function show(){
$this->render(__FUNCTION__);
}
}
class User extends Model {
public function index(){
$this->render(__FUNCTION__);
}
}
Could you go into detail as to why you need this?
I'm not sure what you are trying to do, but especially when you are developing a PHP framework you should restrict yourself to the basic rules of inheritance.
Maybe you could illustrate a little better what you're trying to achieve with this.
Couldn't you simply change it to the following?
class Model {
protected $_type='unspecified';
public function render(){
echo '<br />class: '.$this->_type.' -- function: '.__FUNCTION__;
}
}
class Product extends Model {
public function __construct(){
$this->_type = 'product';
}
public function show(){
$this->render();
}
}
class User extends Model {
public function __construct(){
$this->_type = 'user';
}
public function index(){
$this->render();
}
}
Or is there any reason why that doesn't work for you?
You could move the logic which works out what you are rendering into the superclass, e.g.:
class Model {
public function render($type){
echo '<br />class: '.get_class($this).' -- function: '.$type;
}
public function show() {
$this->render('show');
}
public function index() {
$this->render('index');
}
}
class Product extends Model {
public function show(){
//some stuff
parent::show();
}
}
class User extends Model {
public function index(){
parent::index();
}
}
I don't really recommend this to you, but what you could do is throw an exception and catch it right away.
Then you can use the stack trace of this exception to find out which function called your render method.
I know that it works, but both performancewise and codingwise this is not a good option.
UPDATE:
<?php
class bla {
function test1() {
$this->test2();
}
function test2() {
$method = "";
try {
throw new Exception("bla");
} catch(Exception $e) {
$trace = $e->getTrace();
$method = $trace[1]['function']);
}
echo $method; //will echo test1
}
}
$blub = new bla();
$blub->test1();
Hope you get what I'm trying to illustrate.