Notify on class call - php - php

I want a function that will be called every time a class is referenced (called).
The magic function autoload does a similar thing, but works only if the referenced class doesn't exist.
I want to make a function that will work in any case.
For example:
<?php
class Foo {
static function bar () {
...
}
}
function __someMagicFunction ($name) {
echo 'You called class ' . $name;
}
Foo::bar(); // Output: You called class Foo
I want the output to be "You called class Foo".
How can i do it?
Thanks :)

Well, there's no easy way to do this, but it is possible. Still, the way you'll have to go about achieving this is not to be recommended, as it will result in slow code. However, here's a simple way to do this:
class Foo
{
//protected, not public
protected static function bar ()
{
}
protected function nonStaticBar()
{
}
public function __call($method, array $args)
{
//echoes you called Foo::nonStaticBar
printf('You called %s::%s', get_class($this), $method);
//perform the actual call
return call_user_func_array([$this, $method], $args);
}
//same, but for static methods
public static function __callStatic($method, array $args)
{
$calledClass = get_called_class();//for late static binding
printf('You called %s::%s statically', $calledClass, $method);
return call_user_func_array($calledClass . '::' . $method, $args);
}
}
$foo = new Foo;
$foo->nonStaticBar();//output: You called Foo::nonStaticBar
Foo::bar();//output: You called Foo::bar statically
The reason for __callStatic using get_called_class rather than get_class(self); is that it enables you to declare the magic methods as final, and still have them work as expected in child classes:
class Foobar extends Foo
{}
Foobar::bar();//output: You called Foobar::bar statically
demo
more details on magic methods:
The docs, of course
some previous answers of mine explaining why __call & co are slow
and why you should predeclare properties (same reason as why __call is slow) here

use
public function __construct(){
}

Related

PHP return object instance from __getStatic()

PHP has a magic method __getStatic() that allows overloading of static method calls. I have a class with a fluent interface which performs integrity checks. I call it like this:-
$check = new CheckSomeCondition();
$check->forActive()->sites(array(1,2,3))->check();
However, I would like to call it like this:-
CheckSomeCondition::forActive()->sites(array(1,2,3))->check();
I thought that having this magic method in my base class would allow me to do this:-
public static function __callStatic($method, $args)
{
$instance = new self();
return call_user_func_array(array($instance, $method), $args);
}
But new self() produces an instance of the class that the calling code is in, and not the class which __callStatic() exists in, why is this? and how can I get around it?
I have also tried new static and this does the same thing.
I know this must be possible because Laravel's QueryBuilder has an interface like DB::table()->... and this uses method chaining, returning object instances, not static classes. I have had a look at the Laravel code, but I think they create the instances somewhere else in the application and they are stored in a class member ready to be returned.
The magic method __callStatic is only called for methods which don't exist, so in this case it will simply not run.
Consider the following simplified example:
class Foo
{
public function bar()
{
echo "Running instance method bar()";
}
public static function __callStatic($method, $args)
{
echo "__callStatic called for non-existent method $method";
}
}
Foo::bar();
If you run this (here's an online demo) you will see that it is the "real" bar() method that is called.
There can only be one method named bar on the class, so PHP's only other option would be to complain that bar() should be static - which it does, but non-fatally.
The reason you see an instance of the calling class is not that $instance is instantiated with the wrong class, but because when your method is called non-statically, $this "leaks" from the enclosing scope.
In the following example, $this ends up being the instance of Bar:
class Foo
{
public function doSomething()
{
echo get_class($this);
}
}
class Bar
{
public function doSomethingElse()
{
Foo::doSomething();
}
}
$bar = new Bar();
$bar->doSomethingElse();
Live Demo
As #IMSoP pointed out, __getStatic() is only called if there is no method with the name called - not just if there isn't a static method with the name.
So the workaround to allow calls such as CheckClass::forActive->sites() is to give all the non static method names a prefix such as '_' and have a magic method __call() which will add the prefix in.
This means if I do CheckClass::forActive() the method forActive() doesn't exist, so __getStatic() will be called and will create an instance of the object and try to call the desired method. But the method doesn't exist because we've prefix it, so PHP will call the __call() magic method which will add the prefix and call the prefixed method.
So the 2 functions are:-
public static function __callStatic($method, $args)
{
$instance = new self;
return call_user_func_array(array($instance, $method), $args);
}
public static function __call($method, $args)
{
$method = 'prefix_' . $method;
return call_user_func_array(array($instance, $method), $args);
}
// Then all our method names need to be prefixed, like so:-
public static function prefix_SomeMethod($method, $args)
{
// Do something
return $this;
}

Having Issues with Magic Static Functions

I have a class that I'm trying to create a function that will call a static method that is run through a magic method. The thing is the functions work as long as they are from different types of classes than the class calling them, but if I call a static function of the same class all the function will return is 1.
class Test {
public function static __callStatic($name, $params) {
return 2;
}
public function __call($name, $params) {
return 1;
}
public function Test1() {
return Test::GetTwo();
}
}
class Test2 {
public function Test() {
return Test::GetTwo();
}
}
$t = new Test();
echo $t->Test1(); //prints 1 should be 2
$t2 = new Test2();
echo $t->Test(); //prints 2 as it should
even if the static method GetTwo() returns an object I still get 1 if I'm calling a function in the same scope as Test1(). Any one else run into this?
echo Test::Test1();
You don't need (nor should use) an instance to call a static method. Use the class and the scope resolution operator (::) to do the call.
If you need late static binding use static::Test1();
For an method call on an instance, PHP will try the following:
Find an instance method named X.
Find a magic method __call.
Find a class (static) method named X.
Find a magic class (static) method __callStatic.
In your case, it finds __call at step 2 and goes with that.

Making a method in PHP automatically run some code after being called. Possible?

I'm not really sure if what I am looking for has a name, so it has been a bit difficult for me to search for, so I apologise if what I am asking has already been answered here before.
The situation is that I have an abstract class which has, of course, many other classes which extend it.
The abstract method in the abstract class is called run() and all of the extending classes define this method.
My problem is that I want to call some common code after the run() method has been called, but I want to know if there is a better way to do this.
I could of course just paste my common code into each and every extending class's run() method, but if I do that then it would be a lot of work for me to make simple changes from that point onward.
I could also put my common code into a method in the parent class and then call if from the extending class's run() method with $this.
But my question is, is there a better way to do this, or do I have to either use the $this keyword or paste in the code into each class's?
Here is a small example of what I want to do with my current idea:
abstract class Parent_Class {
public abstract function run();
protected function common_code() {
// Common code here
}
}
class Child_Class {
public function run() {
// Code here
// I want some common code to run after the run method has been called
$this->common_code(); // Is this the best way to do it?
}
}
Or is it possible to somehow tell the class that when the run() method has been called to automatically run the common_code() method?
A far simpler way to do this would to simply have a third method which calls run() and then calls common_code(). Subclasses can then override run() all they want.
abstract class Parent_Class {
public abstract function run();
protected function common_code() {
// Common code here
}
protected function start() {
$this->run();
$this->common_code();
}
}
class Child_Class {
public function run() {
// Code here
}
}
Based on Bradley Forster answer, you can define the method as protected, so when it's called from outside the class, you can intercept the event with php magic __call metod because
__call() is triggered when invoking inaccessible methods in an object context.
and then you can execute that method from the __call function
class A {
public function __call($method, $args){
if(!method_exists($this, $method))
throw new Exception("Call to undefined method ".__CLASS__."::$method()");
echo "doing something BEFORE function 'run' execution\n";
$retval = call_user_func_array(array($this, $method), $args);
echo "doing something AFTER function 'run' execution\n";
return $retval;
}
protected function run() {
echo "function 'run' executed\n" ;
}
}
$a = new A;
$a->run();
The answer given by Amber is nice and simple. But requires you to put your data in run() but call start(). Here is an alternative that allows you to have your code $a->run() in all your scripts, and $a->run() with your common code, but encapsulated in a namespace.
File hooks.php
<?php
// File: hooks.php
namespace hook;
class processHooks {
public function __construct() { /* Fatal Error without constructor */ }
protected function processHooks($_c, $method, $args) {
/* Swap the next two callbacks to run your custom code after */
call_user_func_array("\hook\\{$_c}::{$method}", $args);
return call_user_func_array(array($_c,$method), $args);
}
}
class A {
public function foo() {
echo 'Doing code stuff BEFORE calling child function....<br>';
}
}
File regular_file.php
<?php
// File: regular_file.php
include "hooks.php";
class A extends \hook\processHooks {
/* All that is required is this function
* and the function with common code to be protected
*/
public function __call($method, $args) {
self::processHooks(__CLASS__, $method, $args);
}
protected function foo() {
echo 'Method is called....<br>';
}
}
$a = new A();
$a->foo();
This works beacause method foo of class A in regular_file.php is protected, so it's not callable outside the class, so calling it triggers PHP magic method __call
__call() is triggered when invoking inaccessible methods in an object context.

require_once() in a class

I noticed that if I declare a function inside a class method that has the same name as a outside function I get a error:
function a(){
...
}
class foo{
public function init(){
function a(){ // <- error
...
}
...
}
}
this however would work:
function a(){
...
}
class foo{
public static function a(){
...
}
}
Can I include a set of functions that act as static methods for this class using require_once or something like that?
require_once('file.php'); after class foo{ doesn't work...
PHP allows to nest function declarations in others, but it doesn't actually have nested functions. They always end up in the global scope. So the a() that you define in your init method clashes with the already defined function a().
The static function a() is associated with the class namespace, even if it behaves like a function, not a method.
Invoking a require_once statement in a class definition is not possible. The PHP syntax does not allow for it. Class definitions are special scopes / language constructs, that only allow function or variable declarations within the immediate parsing level. - So PHP does not allow for that (classes and their methods must be declared at once, not assembled), and there are no really nice or advisable workarounds for what you want.
If your class structure allows, you can split the class into several different classes which are part of an inheritance chain:
class foo1 {
public static function a() {}
}
class foo extends foo1 {
public static function b() {}
}
Alternatively, you can use __callStatic() if you are willing to take the performance hit. (Requires PHP 5.3; though if you only need non-static methods, __call is available from 5.0.) Smarty 3 does this IIRC.
class foo {
private static $parts = array('A', 'B');
public static __callStatic($name, $arguments) {
foreach (self::$parts as $part) {
if (method_exists($part, $name)) {
return call_user_func_array(array($part, $name), $arguments);
}
}
throw new Exception();
}
}
class A {
public static function a() {}
}
class B {
public static function b() {}
}
PHP 5.4 will supposedly include traits, which are a more straightforward way of including external code in a class:
class foo {
use A, B;
}
trait A {
public static function a() {}
}
trait B {
public static function b() {}
}
To answer the question: you should first check whether or not the function a has already been implemented by using function_exists:
class foo{
public function init(){
if(!function_exists('a')):
function a(){ // <- will only be declared when it doesn't already exist
...
}
endif;
...
}
}
However, consider this as a very bad coding practice. It will get a mess pretty soon as you have no idea of what's going on exactly and what function will be used. I'd say you'd be better off using a subclass and require_once the appropriate subclass.
Assuming not defining the second "a" method is not acceptable, you'll need to move it outside the init method.
It sounds like your require_once call is the problem (definitely should not be called inside the class). Could you post a full sample including your require_once call that isn't working ?

call a static method inside a class?

how do i call a static method from another method inside the same class?
$this->staticMethod();
or
$this::staticMethod();
self::staticMethod();
More information about the Static keyword.
Let's assume this is your class:
class Test
{
private $baz = 1;
public function foo() { ... }
public function bar()
{
printf("baz = %d\n", $this->baz);
}
public static function staticMethod() { echo "static method\n"; }
}
From within the foo() method, let's look at the different options:
$this->staticMethod();
So that calls staticMethod() as an instance method, right? It does not. This is because the method is declared as public static the interpreter will call it as a static method, so it will work as expected. It could be argued that doing so makes it less obvious from the code that a static method call is taking place.
$this::staticMethod();
Since PHP 5.3 you can use $var::method() to mean <class-of-$var>::; this is quite convenient, though the above use-case is still quite unconventional. So that brings us to the most common way of calling a static method:
self::staticMethod();
Now, before you start thinking that the :: is the static call operator, let me give you another example:
self::bar();
This will print baz = 1, which means that $this->bar() and self::bar() do exactly the same thing; that's because :: is just a scope resolution operator. It's there to make parent::, self:: and static:: work and give you access to static variables; how a method is called depends on its signature and how the caller was called.
To see all of this in action, see this 3v4l.org output.
This is a very late response, but adds some detail on the previous answers
When it comes to calling static methods in PHP from another static method on the same class, it is important to differentiate between self and the class name.
Take for instance this code:
class static_test_class {
public static function test() {
echo "Original class\n";
}
public static function run($use_self) {
if($use_self) {
self::test();
} else {
$class = get_called_class();
$class::test();
}
}
}
class extended_static_test_class extends static_test_class {
public static function test() {
echo "Extended class\n";
}
}
extended_static_test_class::run(true);
extended_static_test_class::run(false);
The output of this code is:
Original class
Extended class
This is because self refers to the class the code is in, rather than the class of the code it is being called from.
If you want to use a method defined on a class which inherits the original class, you need to use something like:
$class = get_called_class();
$class::function_name();
In the later PHP version self::staticMethod(); also will not work. It will throw the strict standard error.
In this case, we can create object of same class and call by object
here is the example
class Foo {
public function fun1() {
echo 'non-static';
}
public static function fun2() {
echo (new self)->fun1();
}
}
call a static method inside a class
className::staticFunctionName
example
ClassName::staticMethod();

Categories