Function assign a parameter that isn't null - php

This is the follow up question on my previous question.
Run a function without a parameter but needed a variable outside of the function - PHP
I recieved this answer
function foo($arg1 = null, $arg2 = null) {
// if they are not set retrieve from a session
$arg1 = ($arg1 !== null) ? $arg1 : $_SESSION['arg1'];
// rinse repeat.
}
So I've thought, maybe I can reduce the line of codes by preventing to call the same variable on every single function.
I've come up with this one.
function foo($arg1 = $_SESSION['user_id'], $arg2 = $_SESSION['campaign_id']) {
//do something
}
Unfortunately, I recieved this error.
Parse error: syntax error, unexpected T_VARIABLE
Is there a reason why it results to this one? I just replaced the null ones with a variable that has a value in it.
Is there any way to assign a function with parameter that has already a value instead of assigning a null ones?
P.S.
I'm trying to output the data using echo $campaign->getName(), so there's no parameter provided when calling the function.
So I'm trying to call a function something like this
function foo($arg1 = $_SESSION['user_id'], $arg2 = $_SESSION['campaign_id']) {
//do something
}
If there's any way to do it without calling the same variable over and over again.
Any help would be appreciated. :)

tl;dr
Don't try that (it doesn't really even work as you see), use proper DI (dependency injection) and pass your external (global) variables as parameters:
// functions should be deterministic — require the arguments in favour of using dynamic defaults
function foo($arg1 /* require it */, $arg2 = 1 /* static scalars as default is no problem */) {
// your code
}
foo($_SESSION["user_id"]); // always pass dynamic arguments, don't fetch them in the function
Intro
It isn't possible to use anything else as default as the so called static scalars. These are literals (strings, integers etc.), constants and (since PHP 5.6) operations on these literals/constants.
So...
I had the same great idea more than two years ago and filed a bug report ... https://bugs.php.net/bug.php?id=60544
Today I think it's a not-so-great idea. Default values are supposed to be static by the language. I doubt the ones who designed PHP hadn't had their reasons.
But there's still a way...
How you can do it (not recommended)
The only workaround here is to use constants.
function foo($arg = ARG) {
var_dump($arg);
}
At the moment where you're sure that the value won't change anymore, define the constant before the first call of the function:
define("ARG", $_SESSION["user_id"]);
Then you can later just call it via foo();.
That's possible due to lazy evaluation of constants here.
The drawback of this method is that you have to define the constant once and then it'll remain immutable for the rest of the scripts run-time.
But I still strongly not recommend it. It's hackish and has major disadvantages.
How you could do it better
You have shown us a way how to do it:
$arg1 = ($arg1 !== null) ? $arg1 : $_SESSION['arg1'];
That absolutely is the correct way. If you really want to do it.
But you still shouldn't do that. You're accessing global scope (superglobals) from a function.
How you should do it
There's one reason why the language designers didn't implement this possibility and it's the same why we shouldn't try to circumvent that in any way by constants or global scope access in the functions.
You really should properly use dependency injection and pass external (global) values to the functions via parameter. (see example in tl;dr section)
This genre of code you're proposing can easily lead to hardly debuggable code as people might not expect that global state is accessed by genuine functions.
That's why functions should have deterministic output for a given input (except if they're explicitly supposed to be non-deterministic, e.g. a function to read a file), that dramatically increases testability and portability.

You can't.
You can only assign literals to function defaults, constant values that cannot change in runtime. That means, "actual strings", numbers (42), hardcoded arrays ([1, 2, 3]), NULL. And not $variables, function() {} or anything else that may be changed at runtime.
Nor you should.
If you function depends on a user ID and a campaign ID, you should pass them into your function, and not rely on them being in SESSION because you can't know if they actually are in there!.
Do not rely on globals.
Why not pass the parameters to the function? It needs them, doesn't it? Would you expect the following function to work without parameters?
add($x, $y)
And just because those parameters are brought from SESSION, database, or the world beyond?
No. The function needs two parameters, and as such, it should ask for and given two parameters.

I have bad news for you, in the form of shorter isn't always better. This is mainly because you're referring to the $_SESSION values as constants, and that's not really good.
A good, solid code is longer because of all the checking and validation that helps avoid unnecessary errors. This is basically what you need to do:
function foo($arg1 = null, $arg2 = null) {
// if condition
if (!$arg1 && isset($_SESSION['arg1']))
$arg1 = $_SESSION['arg1'];
// tenary condition
$arg2 = (!$arg2 && isset($_SESSION['arg2'])) ? $arg2 : $_SESSION['arg2'];
}
If you really want to, you can look for something that will shorten this code by a few letters but it won't really be much different. All those validations are a must and shouldn't be ignored.

Looking at your previous question, I'm guessing you have a number of methods that require the campaign ID and user ID. I would suggest you pass the campaign ID and user ID to the constructor of the Campaign class. Then you can call whatever methods and always have access to them:
<?php
$campaign = new Campaign($db, $_SESSION['user_id'], $_SESSION['campaign_id']);
class Campaign {
private $db;
private $user_id;
private $campaign_id;
public function __construct($db, $user_id, $campaign_id) {
$this->db = $db;
$this->user_id = $user_id;
$this->campaign_id = $campaign_id;
}
public function getName() {
$query = $this->db->prepare("SELECT name FROM campaign WHERE campaign_id = :campaign_id AND user_id = :user_id");
$status = $query->execute(array(':campaign_id' => $this->campaign_id, ':user_id' => $this->user_id));
return ($query->rowCount() == 1) ? $query->fetchObject()->name : false;
}
}

Related

Is global $argv; a good practice or should i avoid it? [duplicate]

This question already has answers here:
Are global variables in PHP considered bad practice? If so, why? [duplicate]
(6 answers)
Closed 5 years ago.
As for me, i avoid using global, but i stumbled about a point, there the use seems to be the best solution. I build this function:
function _get($parameter_name)
{
global $argv; // register the argv array as a global variable
if (isset($argv))
{
parse_str(implode('&', array_slice($argv, 1)), $_GET);
}
return $_GET[$parameter_name];
}
The purpose of this method is to call _get('test') and fetch the value of an argument passed by argv or otherwise an url GET parameter. But i'm not sure about it.
I'm already aware, that the usage of global is bad pratice like mentioned in Are global variables in PHP considered bad practice? If so, why?. But the argv array is a little special. It's automatically filled through the php-cli and only accessible from the called script. If i want to access this variable from within a class method or a function, i need to pass it where, or put it in a public static class member. That would be a solution, but i don't want to write the same lines in every script to pass the array through many functions. That is not really nice. So i'm thinking about this way as another possible solution.
Your opinions about this or maybe a better way i'm not seeing at the moment?
Using global could be confusing. I suggest you something like this to avoid the usage of that keyword for your purpose, abstract of $argv vs $_GET.
class Params
{
static private $args = [] ;
static public function init($args = null)
{
if (! is_null($args)) {
parse_str(implode('&', array_slice($args, 1)), self::$args);
}
if (isset($_GET) && !empty($_GET)) {
self::$args = $_GET ;
}
}
static public function get($parameter_name, $default = null)
{
if (! isset(self::$args[$parameter_name]))
{
return $default ;
}
return self::$args[$parameter_name] ;
}
}
// Usage :
Params::init($argv) ;
$value = Params::get("test") ;
While the advice to avoid global is important and correct, it's important to know why you're avoiding it. Being dogmatic about it for its own sake is counter productive. This is just about the only use case where global is appropriate. $argv is essentially a PHP API, which is only accessible in the global scope. But of course you want to encapsulate the logic of retrieving values from it in a function, instead of having to have that code be global as well. The only choice then in pure functional programming (disregarding OO alternatives) is to import $argv from the global scope.

PHP - is there a way to save an already defind function in a variable?

I am interested in something google couldn't really help me with...
I know that its possible to use anonymous functions and also store functions in a variable in PHP like that
$function = function myFoo() { echo "bar"; }
and call it using the variable: $function();
So far so good but what if I have a function or method declared somewhere but not saved on intializing?
I have a function that shall expect a callable, of course call_user_func() can help me here but then I need to pass the method name in my callback handler which I think is pretty unsafe because in the moment I add the callback I cant say if it really is a function and exists when I store it.
Thatswhy I would like to realize the following szenario:
This function:
function anyFunction() {
echo "doWhatever...!";
}
should be saved in a variable at a later point in time:
$myOtherFunction = get_registered_func("anyFunction");
I know get_registered_func() doesnt exist but I want to know if this is possible somehow!
With this I could now have another function
function setCallback(callable $theCallbackFunction) { }
And use it like this:
setCallback($myOtherFunction);
This would have a great advantage that an exception / a fatal is thrown when the parameter is no function or does not exist.
So in short, is there a way to store a previously defined, already existing function or method in a variable?
PHP's callable meta type can be:
a string
an array
an anonymous function
Only the latter one is somewhat "type safe", i.e. if you get an anonymous function you know it's something you can call. The other two options are merely formalised informal standards (if that makes sense) which are supported by a few functions that accept callbacks; they're not actually a type in PHP's type system. Therefore there's basically no guarantee you can make about them.
You can only work around this by checking whether the callable you got is, well, callable using is_callable before you execute them. You could wrap this into your own class, for example, to actually create a real callable type.
I see no reason why this shouldn't be possible, other than there not being a PHP function to do it. The anonymous function syntax is newly introduced in PHP, I wouldn'be surprised if it was still a little rough around the edges.
You can always wrap it:
function wrap_function ($callback) {
if (is_callable($callback) === false) {
throw new Exception("nope");
}
return function () {
call_user_func($callback, func_get_args());
}
}
$foo = new Foo();
$ref = wrap_function(array($foo, "bar"));
Not a good way, but maybe this helps you:
function foo($a) {
echo $a;
}
$callFoo = 'foo';
$callFoo('Hello World!'); // prints Hello

Pre-declare all private/local variables?

This may be a basic question, but it has kept me wondering for quite some time now.
Should I declare all private/local variables being private? Or is this only necessary for "important" variables?
For instance, I have the (temporary) result of a calculation. Should I pre-declare this variable?
Hope someone can point this out.
Since you're talking about private, protected and public I take it you're talking about properties, instead of variables.
In that case: yes, you should declare them beforehand.
Because of how PHP objects are designed, an array (properties_table) is created on compile time. This array ensures that accessing a given property is as fast as possible. However, if you add properties as you go along, PHP needs to keep track of this, too. For that reason, an object has a simple properties table, too.
Whereas the first (properties_table) is an array of pointers, the latter is a simple key => value table.
So what? Well, because the properties_table contains only pointers (which are of a fixed size), they're stored in a simple array, and the pointers are fetched using their respective offsets. The offsets are stored in yet another HashTable, which is the ce->properties_info pointer.
As bwoebi pointed out to me in the comments: getting the offset (HashTable lookup) is a worst-case linear operation (O(n)) and predefined property lookups are constant-time complex operations (O(1)). Dynamic properties, on the other hand need another HashTable lookup, a worst-case linear operation (O(n)). Which means that, accessing a dynamic property takes in average about twice as long. Authors of the Wikipedia can explain Time-Complexity far better than I can, though.
At first, access modifiers might seem irrelevant. As you go along, you'll soon find that sometimes, you just don't want to take the chance that some property of some object gets modified by some bit of code. That's when you see the value of private.
If an object contains another object, that holds all sorts of settings that your code will rely upon, for example, you'll probably use a getter method to access those settings from the outside, but you'll leave that actual property tucked away nicely using private.
If, further down the line, you're going to add data models and a service layer to your project, there's a good change you'll write an (abstract) parent class, if only for type-hinting.
If those service instances contain something like a config property, you'll probably define that getter in the parent class (to only define it once). private means that only the current class has access to a property, but since you're not going to have an instance of the parent to work with, but an instance of the child, you'll see why protected is invaluable when dealing with larger projects, too.
As far as temporary variables are concerned, be it in methods, functions or anywhere else, you don't have to predeclare them, except for, in certain cases arrays:
public function foo()
{
$temp = $this->getSomeValue();
return $temp ? $temp +1 : null;
}
Is perfectly valid, and wouldn't work any better if you were to write
public function foo()
{
$temp;// or $temp = null;
$temp = $this->getSomeValue();
return $temp ? $temp +1 : null;
}
However, it's not uncommon to see simething like this:
public function bar($length = 1)
{
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
This code relies on PHP being kind enough to create an array, and assign it to $return when the $return[] = rand(); statement is reached. PHP will do so, but setting your ini to E_STRICT | E_ALL will reveal that it doesn't do so without complaining about it. When passing 0 to the method, the array won't be created, and PHP will also complain when it reaches the return $return; statement: undeclared variable. Not only is it messy, it's also slowing you down! You're better off declaring $return as an array at the top of the scope:
public function bar($length = 1)
{
$return = array();//that's it
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
To be on the safe side, I'd also check the argument type:
/**
* construct an array with random values
* #param int $length = 1
* #return array
**/
public function bar($length = 1)
{
$length = (int) ((int) $length > 0 ? $length : 1);//make length > 0
$return = array();
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
In most if not all cases: yes.
If the variables are class properties they absolutely should be declared before use.
If the variable is local to a function, declare it in that function before you use it. Function variables are confined to the function's scope (local variables). They don't have to be declared before use but it's good practice to do so, and it gets rid of a warning message if you do. If they are not used anywhere else, they should not be properties though,
If you are using it in the context of the whole class, then yes, you should define your variable as a member of the class.
However, if you are talking about a local variable within the context of a single function and the variable does not need to be used elsewhere (or is not returned), then no.
Essentially you need to determine the importance and scope of your variable before deciding whether to make it a class property or not.
For example:
<?php
class Test {
private $test; // Private property, for use in the class only
public $public_test; // Public Property, for use both internally and external to the class as a whole
public function testing() {
$local = 5; // Local variable, not needed outside of this function ever
$this->test = rand(1, 5);
$calc = $local * $this->test; // Local variable, not needed outside of this function ever
$this->public_test = $calc / 2; // The only thing that the whole class, or public use cares about, is the result of the calculation divided by 2
}
}
It's generally a good rule of thumb for variables to define and initialize them before use. That includes not only definition and initial value but also validation and filtering of input values so that all pre-conditions a chunk of code is based on are established before the concrete processing of the data those variables contain.
Same naturally applies to object members (properties) as those are the variables of the whole object. So they should be defined in the class already (by default their value is NULL in PHP). Dynamic values / filtering can be done in the constructor and/or setter methods.
The rule for visibility is similar to any rule in code: as little as necessary (the easy rule that is so hard to achieve). So keep things local, then private - depending if it's a function variable or an object property.
And perhaps keep in the back of your mind that in PHP you can access private properties from within the same class - not only the same object. This can be useful to know because it allows you to keep things private a little bit longer.
For instance, I have the (temporary) result of a calculation. Should I pre-declare this variable?
This is normally a local variable in a function or method. It's defined when it receives the return value of the calculation method. So there is no need to pre-declare it (per-se).
...
function hasCalculation() {
$temp = $this->calculate();
return (bool) $temp;
}
...
If the calculation is/was expensive it may make sense to store (cache) the value. That works easily when you encapsulate that, for example within an object. In that case you'll use a private property to store that value once calculated.
Take these rule with a grain of salt, they are for general orientation, you can easily modify from that, so this is open to extend, so a good way to keep things flexible.

Do I need to define functions before I use them in object-oriented PHP?

Not sure if I phrased the question correctly but let me explain. In a procedural program, for example:
function getUserId()
{
// some stuff
return $someUserId;
}
function getUsername()
{
$id = getUserId();
$query = mysql_query(" SELECT * FROM users WHERE id = '$id' ");
while ($row = mysql_fetch_assoc($query))
{
return $row['username'];
}
}
In the above, the getUsername function called the getUserId function. Since that function was called it must be above the one that called it, otherwise it won't work.
What I would like to know is, in object oriented programming, does the order of functions (methods) in a class matter? Can I call a method within another method even if the method being called is defined further down in the script?
The order of the functions don't matter, for several reasons:
The methods are not executed at compile time, so the compiler can "look ahead" for functions that might not exist yet. (Note: this is an oversimplification...)
PHP is a dynamic language, in that functions don't even have to exist at compile time. They can be loaded dynamically during the run time.
PHP loads methods by name, so it will look for a method that matches the name during runtime.
An example of the third case is:
$object = new MyObject();
$method = 'my_method';
echo $object->${my_method}();
That will call the method my_method, if it exists, on the object $object, which is an instance of the MyObject class. (If that method doesn't exist, it will throw a runtime exception.)
From technical standpoint - it does not matter at all. All that matters is readability and easy of modification, so it is up to you to decide what works best for you. You may want to order functions chronologically, alphabetically, or, sometimes, by purpose. IMHO, the best way is to order them alphabetically - it makes it easier to search for them in code navigation tools.
Depends on the language.
In JavaScript for example, your getUsername() function can be defined first, so long as it is called after getUserId() has been defined.
In Java as another example, it generally does not matter (except for static initilization blocks)
Even in procedural style functions don't need to be declared in order. They only need to exist at the time they are called. This will work perfectly fine, because neither function is actually ever called:
function foo() {
bar();
}
function bar() {
}
The same goes for OOP, a function must exist when it is called. In which order they are declared is irrelevant.
You can call them logically in any order. Some languages enforce an order of declaration which may/maynot be different. But at the root, if you are using a module/class/chunk of code that declares a number of functions or methods you may call them entirely willy nilly.

Documenting implicit input parameters such as $_SESSION

If a function relies on $_SESSION['some_var'] then the header comment out to make that clear. How do you do it? Just as text, or what?
Or even #param?
You could maybe use #uses to document superglobals
Wow, I never even thought about that. I don't even doc things like that. I would say to just state it in the method detail like
/**
* Takes the some_var session variable and uses it to solve world hunger
* #return food
*/
Makes the most sense to me.
There is #global, but that seems to indicate the creation of a global var. I think #param should only refer to method parameters passed to the method. There is no #note, that I know of.
#global has two usages: to denote a global var's definition, and to highlight a global's usage in a method. This second usage fits your use case.
However, assuming that you are referencing $_SESSION['some_var'] directly in that method, and never denoting it via the "global" keyword, it's possible that phpDocumentor's #global tag won't find it when the method is parsed. As such, #uses is probably the best alternative as a means to highlight the method's reliance on that superglobal.
[1] -- http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.global.pkg.html
If your code depends on something global, or external, to be present in order to work (for example, it requires the sqlite to be installed) you can use #use as Nev mentioned.
HOWEVER...
In general, I would say it is a bad practice to have a function populate or use global variables (or use superglobals), as it breaks the encapsulation of the function and creates a strong dependency between the code inside the function and outside.
If any code external to the function is supposed to create or access those globals, the values should instead be passed as parameters to the function.
For example, instead of
function doMagic(){
if ($_SESSION['use_black_magic'] == true){ // var coming from the outside
$_SESSION['magic_results'] = 'dead chicken';
}else{
$_SESSION['magic_results'] = 'unicorn';
}
}
$_SESSION['use_black_magic'] = false;
doMagic();
echo $_SESSION['magic_results']; // (unicorn) variable set within doMagic()
it should be
function doMagic( $use_black_magic = true ){
if ($use_black_magic == true){
return 'dead chicken';
}else{
return 'unicorn';
}
}
$magic_results = doMagic( false );
echo $magic_results; // unicorn
This way, doMagic() doesn't need to know anything about where the results are to be stored, nor where to find the parameter value. And the external code, doesn't need to know that the function doMagic() is doing something with $_SESSION variables.
As soon as your code grows just a little bit, maintaining, sharing, debugging, and extending this kind of code becomes a nightmare...
http://en.wikipedia.org/wiki/Separation_of_concerns

Categories