im just learning php
Im trying to add a log with comments to my functions output.
Right now it looks like this:
//the function
function add1($x){
if($GLOBALS['logging'] === 'on'){ $log[] = 'Adding 1 to '.$x;};
$a = $x + 1;
if($GLOBALS['logging'] === 'on'){
$return[] = $a;
$return[] = $log;
return $return;
}else{ return $a; };
};
//calling the function
if($GLOBALS['logging'] === 'on'){
$return = add1($x);
$number = $return[0];
$log = $return[1];
}else{ $number = add1($x); };
Im kinda annoyed by the fact i need to retype this if statement.
So i made a seperate function for returning the function
which looks like this:
//function
function log_return($data = 'x', $log = 'x'){
if($GLOBALS['logging'] === 'on'){
if($data !== 'x') $return[] = $data;
if($log !== 'x') $return[] = $log;
return $return;
} return $data;
};//function end
And returning it with:
return $return = isset($log) ? log_return($data, $log) : log_return($data);
Now my quastion is: Is there a way to call a function with function..
like:
call_function(add1($x));
so i can return it either with log or without..
Given the answer https://stackoverflow.com/a/2700760/5387193 - this should work:
function add1($a)
{
// add1 code goes here
}
function call_function($name, $param)
{
$name($param);
}
call_function('add1', $x);
On a side note, your variable and function names aren't very intuitive. Perhaps you should study how to write good quality readable code. I recommend reading chapter 9 of Refactoring by Martin Fowler, it's quite good. You can find a PDF version on the web.
Another note, your return statement return $return = isset($log) ? log_return($data, $log) : log_return($data); has a unnecessary assignment to $return. The code should simply read
return isset($log) ? log_return($data, $log) : log_return($data);
Yes, it is possible. To simplify:
function first($x) {
return $x+1;
}
function second($y) {
return $y+1;
}
echo second(first(1)); // Returns 3, ie. 1+1+1
As gview said in his comment, don't use global variables. Argument lists exist for several reasons, included but not limited to making code easier to read, edit, and debug. The same goes for function and variable names.
Moreover, your code is very messy. It can be consolidated:
function addTo($currentValue, $valueToAdd, $logging = 0)
{
if ($logging) {
logWrite('addTo', "Adding $valueToAdd to $currentValue");
return $currentValue + $valueToAdd;
} else {
return $currentValue;
}
}
function logWrite($operation, $message)
{
$log = getLog(); // maybe it's a file, or DB record or something
// perform the write, depending on your implementation
}
$number = addTo($someStaringValue, $someOtherValue, 1);
All of this said, logging should not control program flow. In other words, whether something is logged by the system or not should have no bearing on what your code is trying to do. I really think you need to take a broader view of what you're trying to do and break it up into components.
At best, your code should tell a logger to log info, and the logger itself should determine if logging is actually turned on. If it is, the info is logged. If not, then the code that calls on the logger still works and goes about its business.
Related
This question already has answers here:
How to use return inside a recursive function in PHP
(4 answers)
Closed 9 months ago.
I have a problem with a recursive function in PHP which returns a JSON object. When the the condition is met to run the function a second time I always get an empty object as result {}. Everything is executed as it would be in the first run, but I always get an empty result.
Here is my code (very much simplified, yet functioning):
public function run()
{
$result = null;
// .......
// there is alot other stuff here, that all runs
// perfectly through also the second run
// ......
// Conditional Routing
if($this->wfProfile->autoprocess){
// select new wfProfile and go again.
$this->autoprocess(function($data){
if($data['error']==0){
$result = null;
$this->run(); // from here we start over !
}else{
return $data;
}
});
}else{
return ['error'=>0,'message'=>'all good']; // this is where it should go at the end of second loop
}
}
There is no place in the whole class, that would return an empty JSON object. Something must be here, that I'm doing wrong or what I'm overseeing.
Edit (I don't think this helps)
private function autoprocess($callback)
{
if(is_callable($callback)){
$possibleWFprofiles = WfProfile::where('statusNow', $this->wfRequest->status)->where('conditionalRouting', 1)->get();
if($possibleWFprofiles->count() == 0){
// configuration error....
$result = ["error"=>1, 'message'=>"Unable to find Conditional Routing enabled WfProfiles: ".$this->wfRequest->status];
}
foreach($possibleWFprofiles as $possibleWfProfile){
if(array_search($possibleWfProfile->crFieldname, $this->wfRequestFields)===false){
// fieldname wrongly configured
$result = ["error"=>1, 'message'=>"Unable to find field ".$possibleWfProfile->crFieldname];
}
// see if this is the right one
if($this->wfRequest[$possibleWfProfile->crFieldname] == $possibleWfProfile->crValue){
$this->wfProfile = $possibleWfProfile;
$result = ['error'=>0,'message'=>'Off to loop 2'];
}
}
call_user_func($callback, $result);
}
}
When you make a return $data, inside a anonymous function, it will not be a run's return.
You are not doing nothing with this return in your autoprocess function.
You need to return something in autoprocess and then return in your if:
if($this->wfProfile->autoprocess){
// select new wfProfile and go again.
return $this->autoprocess(function($data){
if($data['error']==0){
$result = null;
return $this->run(); // from here we start over !
}else{
return $data;
}
});
}else{
return ['error'=>0,'message'=>'all good']; // this is where it should go at the end of second loop
}
You need to return your value, for example take this:
function callback($func, $val) {
return call_user_func($func, $val);
}
function run($val) {
if ($val < 10) {
callback(function($val) { return run($val + 1); }, $val);
}
return $val;
}
print(run(0));
this will print empty, but if you do:
function callback($func, $val) {
return call_user_func($func, $val);
}
function run($val) {
if ($val < 10) {
return callback(function($val) { return run($val + 1); }, $val);
}
return $val;
}
print(run(0));
it will print 10
Your function:
public function run()
{
$result = null;
// lets say this is true...
if($this->wfProfile->autoprocess){
// now we are here, where does this return a value???
$this->autoprocess(function($data){
// if it goes here, it never returns a value.
if($data['error']==0){
$result = null;
$this->run(); // from here we start over !
}else{ // if it returns here it still just returns to
// $this->autoprocess, which might return to the
// original run function, but you don't seem to be
// returning its return either...
return $data;
}
});
}else{
return ['error'=>0,'message'=>'all good']; // this is where it should go at the end of second loop
}
}
At the end I chose the imho less elegant way to solve this, so I used goto instead of calling the function again. This is easy to read and to debug/extend in future. So here we go:
public function run()
{
startover:
$result = null;
// more stuff going on here
// Conditional Routing
if($this->wfProfile->autoprocess){
// select new wfProfile and go again.
$result = $this->autoprocess();
if($result['error']==0){
goto startover; // easiest way :-)
}else{
return $result;
}
}else{
return ['error'=>0,'message'=>'all good'];
}
}
and here the autoprocess function
private function autoprocess()
{
$possibleWFprofiles = WfProfile::where('statusNow', $this->wfRequest->status)->where('conditionalRouting', 1)->get();
if($possibleWFprofiles->count() == 0){
// configuration error....
return ["error"=>1, 'message'=>"Unable to find Conditional Routing enabled WfProfiles: ".$this->wfRequest->status];
}
foreach($possibleWFprofiles as $possibleWfProfile){
if(array_search($possibleWfProfile->crFieldname, $this->wfRequestFields)===false){
// fieldname wrongly configured
return ["error"=>1, 'message'=>"Unable to find field ".$possibleWfProfile->crFieldname];
}
// see if this is the right one
if($this->wfRequest[$possibleWfProfile->crFieldname] == $possibleWfProfile->crValue){
$this->wfProfile = $possibleWfProfile;
return ['error'=>0,'message'=>'Off to loop 2'];
}
}
}
I'm working with a third-party class, and I need to be able to run a section of code one of two ways, depending...
$reader->get()->first()->each(function($obj)
{
// Do stuff
}
OR
$reader->get()->each(function($obj)
{
// Do stuff
}
I've always been able to call properties variably with something like...
$a = 1;
$obj->{"$a"}
But unfortunately the below doesn't work...
if (some scenario)
{
$a = "get()->first()";
}
else
{
$a = "get()";
}
$reader->{"$a"}->each(function($obj)
My problem is i'm not sure how to phrase the question for google...I'm assuming there's a solution for the above problem.
Thanks in advance for any help!
You can only use ->{$variable} for the names of properties and methods of the class itself, you can't put PHP syntax like -> in there. What you can do is use function variables:
function get_all($reader) {
return $reader->get();
}
function get_first($reader) {
return $reader->get()->first();
}
$a = 'get_all'; // or $a = 'get_first';
$a($reader)->each(function($obj) {
// do stuff
});
Alternative to Barmar's answer, which imho is a bit clearer.
$it = function($obj) {
// do stuff
});
if (some_scenario) {
$reader->get()->first()->each($it);
} else {
$reader->get()->each($it);
}
One more solution:
if (some_scenario) {
$foo = $reader->get()->first();
} else {
$foo = $reader->get();
}
$foo->each(function($obj) {
// do stuff
});
This is more or less a readability, maintainability and/or best practice type question.
I wanted to get the SO opinion on something. Is it bad practice to return from multiple points in a function? For example.
<?php
// $a is some object
$somereturnvariable = somefunction($a);
if ($somereturnvariable !== FALSE) {
// do something here like write to a file or something
}
function somefunction($a) {
if (isset($a->value)) {
if ($a->value > 2) {
return $a->value;
} else {
return FALSE;
} else {
// returning false because $a->value isn't set
return FALSE;
}
}
?>
or should it be something like:
<?php
// $a is some object
$somereturnvariable = somefunction($a);
if ($somereturnvariable !== false) {
// do something here like write to a file or something
}
function somefunction($a) {
if (isset($a->value)) {
if ($a->value > 2) {
return $a->value;
}
}
return FALSE
}
?>
As a matter of practice, I always try to return from ONE point in any function, which is usually the final point. I store it in a variable say $retVal and return it in the end of the function.It makes the code look more sane to me.
Having said that, there are circumstances where say, in your function as the first line you check if a var is null and if yes you are returning. In this case, there is no point in holdin on to that variable, then adding additional checks to skip all the function code to return that in the end.
So...in conclusion, both ways works. It always depends on what the situation is and what you are more comfortable with.
Quick question to do with php functions, it may sound silly to some of you but I dont want to get in to bad habits. Is there anything wrong with doing the following?
function do_something($val)
{
$a = 1;
if ($val==$a)
{
return true;
}
return false;
}
Instead of;
function do_something($val)
{
$a = 1;
if ($val==$a)
{
return true;
}
else
{
return false;
}
}
Sorry guys I think my example isn't great. Basically the function could insert data into a database or send an email etc. With these functions I may only need to now whether it was successful or not by returning true or false. I wanted to know whether its suitable that I can use the shorter method instead of the if-else block.
I hope that makes it clearer.
Not really. Both works the same. However, it would be much cleaner to write it like this:
function do_something($val)
{
$a = 1;
return ($val==$a) ? true : false;
}
That's totally cool, because when returning a value, the function is left and it doesn't matter what follows.
But you could shorten this with
function do_something($val)
{
$a = 1;
return $val == $a; // this condition will be evaluated to true/false
}
The shortest way to do it:
function do_something($val)
{
return ($val==1) ;
}
No, that is perfectly fine, and in fact advised in multiple cases. :)
I'm stuck in Drupal Panels / PHP Access plugins.
At least, now I found the three conditions to create my final snippet. the purpose of it is to return TRUE; if "condition1 is TRUE" OR "condition2 is TRUE" OR "condition3 is TRUE". I found a lot of similar questions, but the last condition force me to post here to find the right way to do this.
Condition 1:
// At least $view1->result has result.
$view1 = views_get_view('sp_onglet_videos');
$view1->set_display('views-tab-embed_1');
$output1 = $view1->preview();
if ($view1->result) {
return TRUE;
}
Condition 2 (same thing):
// At least $view2->result has result.
$view2 = views_get_view('sp_onglet_audio');
$view2->set_display('views-tab-default');
$output2 = $view2->preview();
if ($view2->result) {
return TRUE;
}
Condition 3 is more complex:
// Checks for content in the field field_txt_videos.
if (isset($contexts['argument_nid_1']->data-> field_txt_videos)) {
$field = $contexts['argument_nid_1']->data-> field_txt_videos;
if (is_null($field)) {
return FALSE;
}
if (is_array($field)) {
foreach ($field as $key => $val) {
if (is_array($val)) {
$field[$key] = array_filter($val);
}
}
$field = array_filter($field);
return count($field);
}
if (is_string($field) && trim($field) == '') {
return FALSE;
}
if ($field) {
return TRUE;
}
return FALSE;
}
I would like to have something clean (and functional) like this:
if ($view1->result && $view2->result && $field) {
return TRUE;
}
But it's to tricky for my php knowledge. Need a little help !
You want to save the result of the 3rd condition (into a variable) and use this result to run your final condition/query. But you can query the 3rd condition if it is a function.
It is better to properly space your code and use plenty of newlines.
However, PHP does have some pretty cool tricks to do assignment inside conditional statements.
if(($view1 = views_get_view('sp_onglet_videos')) AND $view1->set_display('views-tab-embed_1') AND ($output1 = $view1->preview()) AND $view1->result) return TRUE;
However, as you can see this code is a mess - don't do it unless your assignment is really small. Take this simple security check at the top of a PHP file:
<?php defined('BASE_PATH') OR die('Not Allowed');