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.
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
I'm looking for a better way of writing this. I feel like there must be a better way?
public static function logClick($lid)
{
$clickId = link::find($lid);
$clicks = click::find($clickId->click_id);
$c = $clicks->clicks;
$c++;
$clicks->clicks = $c;
$clicks->save();
return $clicks;
}
Models:
class link extends Model
{
public function click()
{
return $this->hasOne('App\click', 'id' ,'click_id');
}
}
class click extends Model
{
public function link()
{
return $this->hasOne('App\link');
}
}
Btw. everything works, just looking to improve my code writing :)
public static function logClick($lId){
click::whereHas('link', function($q)use($lId){
$q->where('id', $lId);
})
->increment('clicks');
}
This should do
EDIT: if you want to return the clicks number
public static function logClick($lId){
$click = click::whereHas('link', function($q)use($lId){
$q->where('id', $lId);
})
->increment('clicks');
return $click->clicks;
}
This one liner has the advantage of being a single query. In case $q->where('id', $lId); doesn't work, make sure to use $q->where('links_table_name.id', $lId);
public static function logClick($lid)
{
$clicks = link::find($lid)->click;
$clicks->increment('clicks');
return $clicks;
}
I cannot workout why this script always returns 0. If I change it to echo getSKU() it works, but Quantity, Price or Name never seems to work. If anybody has any ideas please, please help this is irritating the life out of me!
<?php
session_start();
$sku = "0001";
if (!isset($_SESSION[$sku])) {
$_SESSION[$sku] = new product($sku, 5);
} else {
}
echo $_SESSION[$sku]->getQuantity();
class product {
var $sku;
var $name;
var $price;
var $quantity;
function __construct($par1, $par2) {
$this->sku = $par1;
$this->quantity = $par2;
}
function setSKU($x) {
$this->sku = $x;
}
function getSKU() {
echo $this->sku;
}
function setName($x) {
$this->name = $x;
}
function getName() {
echo $this->name;
}
function setPrice($x) {
$this->price = $x;
}
function getPrice() {
echo $this->price;
}
function setQuantity($x) {
$this->quantity = $x;
}
function incrementQuantity() {
$this->quantity++;
}
function getQuantity() {
echo $this->quantity;
}
}
You should use return instead of echo. Your get...-methods currently don't return something (just implicitly null), they just echo the value you want to return.
To fix this, just replace in every get...-method echo with return - i.e.
function getQuantity() {
return $this->quantity;
}
In addition to that, you should know, that you cant store objects in $_SESSION (actually you could, but then you have to implement the magic __sleep and __wakeup-methods..).
You should think about other solutions to store your products inside the session (i.e. serialize them)
you shouldn't echo your attribute in get methodes
echo $this->Variable;
you should always return them.
return $this->Variable;
return returns program control to the calling module. Execution
resumes at the expression following the called module's invocation
for more information on return check the documentation here
while the issues brought up in the other answers should definitely be addressed, to answer your question i believe the quantity is probably not set. can you try adding this line?
$_SESSION[$sku]->setQuantity(5);
$_SESSION[$sku]->getQuantity();
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();
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();