if have a bunch of functions :
function one () { ... }
function two () { ... }
...
function ten () { ... }
is there a way to execute a pre and post function for each ten functions above WITHOUT MODIFY THEM?
for instance,
function one () { print '1'; }
function pre () { print 'start'; }
function post () { print 'finish'; }
set_pre_function (one, pre);
set_post_function (one, post);
one();
result :
start
1
finish
What about this approach?
You will need to add your functions to the class, and make them private or protected, but you call them directly.
class prePostClass {
private $preFunc;
private $postFunc;
public function set_pre_function($func) {
$this->preFunc = $func;
}
public function set_post_function($func) {
$this->postFunc = $func;
}
public function __call($name, $arguments) {
if (!is_null($this->preFunc)) {
$this->preFunc();
}
$return = call_user_func_array(__CLASS__ . '->' . $name, $arguments);
if (!is_null($this->postFunc)) {
$this->postFunc();
}
return $return;
}
}
try call_user_func :
function callfunc($name,$params=false){
//Call pre
//Call real function
call_user_func($name,$params);
//and the last, call post
}
thank #KatrinRaimond :)
Like this. I haven't used it but its supposed to work.
function one ()
{
global $pre_one;
global $post_one;
$pre_one();
/* code here */
$post_one();
}
func_one() { }
func_two() {}
$pre_one = 'func_one';
$post_one = 'func_two';
You can accomplish this by simply calling your relevant pre and post functions at the beginning and end of the one function. That is, if they need to be their own functions.
function pre () { print 'start'; }
function post () { print 'finish'; }
function one () { pre(); print '1'; post(); }
one();
Related
Say I have to similar function :
public function auth(){
return $someResponse;
}
public function collect(){
return $someOtherResponse
}
Question : When one of the response get passed to another class, is there any way to check which function returned the response ?
In a purely object-oriented way, wanting to attach information to a value is akin to wrapping it into a container possessing context information, such as:
class ValueWithContext {
private $value;
private $context;
public function __construct($value, $context) {
$this->value = $value;
$this->context = $context;
}
public value() {
return $this->value;
}
public context() {
return $this->context;
}
}
You can use it like this:
function auth()
{
return new ValueWithContext($someresponse, "auth");
}
function collect()
{
return new ValueWithContext($someotherrpesonse, "collect");
}
This forces you to be explicit about the context attached to the value, which has the benefit of protecting you from accidental renamings of the functions themselves.
As per my comment, using arrays in the return will give you a viable solution to this.
It will allow a way to see what has been done;
function auth()
{
return (array("auth" => $someresponse));
}
function collect()
{
return (array("collect" => $someotherrpesonse));
}
class myClass
{
function doSomething($type)
{
if (function_exists($type))
{
$result = $type();
if (isset($result['auth']))
{
// Auth Used
$auth_result = $result['auth'];
}
else if (isset($result['collect']))
{
// Collect used
$collect_result = $result['collect'];
}
}
}
}
It can also give you a way to fail by having a return array("fail" => "fail reason")
As comments say also, you can just check based on function name;
class myClass
{
function doSomething($type)
{
switch ($type)
{
case "auth" :
{
$result = auth();
break;
}
case "collect" :
{
$result = collect();
break;
}
default :
{
// Some error occurred?
}
}
}
}
Either way works and is perfectly valid!
Letting the two user defined functions auth() & collect() call a common function which makes a call to debug_backtrace() function should do the trick.
function setBackTrace(){
$backTraceData = debug_backtrace();
$traceObject = array_reduce($backTraceData, function ($str, $val2) {
if (trim($str) === "") {
return $val2['function'];
}
return $str . " -> " . $val2['function'];
});
return $traceObject;
}
function getfunctionDo1(){
return setBackTrace();
}
function getfunctionDo2(){
return setBackTrace();
}
class DoSomething {
static function callfunctionTodo($type){
return (($type === 1) ? getfunctionDo1() : getfunctionDo2());
}
}
echo DoSomething::callfunctionTodo(1);
echo "<br/>";
echo DoSomething::callfunctionTodo(2);
/*Output
setBackTrace -> getfunctionDo1 -> callfunctionTodo
setBackTrace -> getfunctionDo2 -> callfunctionTodo
*/
The above function would output the which function returned the response
Is there another way to assign or return a function without executing it? I think this is not the best solution ...
class Foo {
public function getDisplayFunction() {
return function() {
$this->display();
};
}
private function display() {
echo 'something';
}
}
$display = (new Foo())->getDisplayFunction();
//and execute it
$display();
I get it ... after trying 100 of things and 1 hour searching. Here my answer for all who looking also for the solution.
public function getDisplayFunction() {
return function() {
return $this->display();
}
}
is the same as:
public function getDisplayFunction() {
return [$this, 'display'];
}
the advantage is you don't have to pass args with this solution. That was the reason for the question.
I have a strange problem. I am writing a callback-like system where some code calls a function in a class which adds the function to an array and then later on executes it. Here is my code:
class BaconClass {
private $array;
public function __construct() {
$this->array = array();
}
public function AddBacon($function) {
array_push($this->array, $function);
}
/* ... */
public function GetBacon() {
foreach($this->array as $function) {
echo $function();
}
}
}
Then I have some other code like this:
$bacon = new BaconClass();
$bacon->AddBacon(function() {
echo "Om nom nom";
});
/* And somewhere else I might have */
$bacon->AddBacon(function() {
echo "I like bacon";
});
/* And then after all of this I have */
$bacon->GetBacon();
This code will only print:
I like bacon
I have made sure that the array being passed to the AddBacon function is actually working, but whenever I use var_dump to see what is inside the array after I add an element to it, it always shows one object, which is always the latest one added.
Why is the code overwriting the previous element? If there is a better way to implement this code, I am open to suggestions.
What I have tried
I have tried using $this->array[] = $function, and I have also tried using $this->array[count($this->array)] = $function. Neither are working.
Just tested the provided code in php console, got this output;
class BaconClass {
private $array;
public function __construct() {
$this->array = array();
}
public function AddBacon($function) {
array_push($this->array, $function);
}
/* ... */
public function GetBacon() {
foreach($this->array as $function) {
echo $function();
}
}
}
$bc = new BaconClass();
$bc->AddBacon(function() {echo 'something'; });
$bc->AddBacon(function() {echo 'something else'; });
$bc->GetBacon();
// outputs: somethingsomething else
Seems to be working fine to me
Is it possible to overwrite the already set register_shutdown_function stack? Something like:
function f1(){
echo "f1";
}
function f2(){
echo "f2";
}
register_shutdown_function("f1");
echo "actions here";
register_shutdown_function("f2");
call_to_undefined_function(); // to "produce" the error
In this case I want the script to only call f2(). Is this possible?
You can't do it straight, but there's always a workaround:
$first = register_cancellable_shutdown_function(function () {
echo "This function is never called\n";
});
$second = register_cancellable_shutdown_function(function () {
echo "This function is going to be called\n";
});
cancel_shutdown_function($first);
Output:
$ php test.php
This function is going to be called
The code:
function register_cancellable_shutdown_function($callback)
{
return new cancellable_shutdown_function_envelope($callback);
}
function cancel_shutdown_function($envelope)
{
$envelope->cancel();
}
final class cancellable_shutdown_function_envelope
{
private $callback;
public function __construct($callback)
{
$this->callback = $callback;
register_shutdown_function(function () {
$this->callback && call_user_func($this->callback);
});
}
public function cancel()
{
$this->callback = false;
}
}
This is not possible. PHP has a remove_user_shutdown_function PHPAPI function, but this is not exposed to userland code.
from the php doc page on register_shutdown_function():
Multiple calls to register_shutdown_function() can be made, and each
will be called in the same order as they were registered. If you call
exit() within one registered shutdown function, processing will stop
completely and no other registered shutdown functions will be called.
so this means that if you want to only call function f2 you can pass it in to an exit() call in an exception handler. Multiple calls to register_shutdown_function() will call all of the functions in order, not just the last registered. Since there doesn't seem to be any sort of unregister_shutdown_function() this is what I suggest.
Other option is to use the following function:
function register_named_shutdown_function($name, $callback)
{
static $callbacks = [];
$callbacks[$name] = $callback;
static $registered;
$registered || $registered = register_shutdown_function(function () use (&$callbacks) {
array_map(function ($callback) {
call_user_func($callback);
}, $callbacks);
}) || true;
}
Sample usage:
register_named_shutdown_function("first", function () {
echo "Never executed\n";
});
register_named_shutdown_function("second", function () {
echo "Secondly executed\n";
});
register_named_shutdown_function("first", function () {
echo "Firstly executed\n";
});
Outputs:
Firstly executed
Secondly executed
I have this problem too, and I resolved this as:
function f1(){
if (defined('CALL1') && CALL1===false) return false;
echo "f1";
}
function f2(){
echo "f2";
}
register_shutdown_function("f1");
echo "actions here";
define('CALL1', false);
register_shutdown_function("f2");
call_to_undefined_function();
Basically, what I want to do is create a class called Variables that uses sessions to store everything in it, allowing me to quickly get and store data that needs to be used throughout the entire site without working directly with sessions.
Right now, my code looks like this:
<?php
class Variables
{
public function __construct()
{
if(session_id() === "")
{
session_start();
}
}
public function __set($name,$value)
{
$_SESSION["Variables"][$name] = $value;
}
public function __get($name)
{
return $_SESSION["Variables"][$name];
}
public function __isset($name)
{
return isset($_SESSION["Variables"][$name]);
}
}
However, when I try to use it like a natural variable, for example...
$tpl = new Variables;
$tpl->test[2] = Moo;
echo($tpl->test[2]);
I end up getting "o" instead of "Moo" as it sets test to be "Moo," completely ignoring the array. I know I can work around it by doing
$tpl->test = array("Test","Test","Moo");
echo($tpl->test[2]);
but I would like to be able to use it as if it was a natural variable. Is this possible?
You'll want to make __get return by reference:
<?php
class Variables
{
public function __construct()
{
if(session_id() === "")
{
session_start();
}
}
public function __set($name,$value)
{
$_SESSION["Variables"][$name] = $value;
}
public function &__get($name)
{
return $_SESSION["Variables"][$name];
}
public function __isset($name)
{
return isset($_SESSION["Variables"][$name]);
}
}
$tpl = new Variables;
$tpl->test[2] = "Moo";
echo($tpl->test[2]);
Gives "Moo".