I am creating some widget for Word Press, but maybe this is standard PHP question, because it is related to some MVC pattern. I have some HTML that i need to output on page but that HTML is for now i inside function, i would like to transfer it to partial, because in the future there can be lots of more HTML, and if I make it like this it will be lots of spaghetti code.Here is what i have for now
class motractrucks extends WP_Widget{
function widget($args, $instance, $defaults){
echo '<p>'.$value1.'<p>';
echo '<p>'.$value2.'<p>';
echo '<p>'.$value3.'<p>';
echo '<p>'.$value4.'<p>';
echo '<p>'.$value5.'<p>';
echo '<p>'.$value6.'<p>';
}
}
This is just simple example, I have modified function easy that you can understand what i need, i was thinking to do something like, but how to pass values form inside function in that view?
class motractrucks extends WP_Widget{
function widget($args, $instance, $defaults){
include 'partials/userValues.php';
}
}
And pass all values to that partial, any good idea and best code practice will be nice.
The part of this question that specifically pertains to PHP is the variable scope. PHP functions have a local scope. So variables used inside those functions are considered to be local variables by default. Unless you explicitly import a variable from the global scope into the function's local scope via the global keyword, it's local. In your examples those variables are all undefined.
Also, using echo inside a function is never considered good practice, but I can't speak specifically to the WordPress aspect of your code as I'm not that familiar with WordPress.
Functions should take inputs as arguments and should return values as output. That's typically what you would consider good practice.
function foo($var1, $var2, $var3) {
return <<<HTML
<p>$var1</p>
<p>$var2</p>
<p>$var3</p>
HTML;
}
As far as including files for use in templates, that's usually fine in PHP. When you're doing those includes inside of a function it becomes easier to contain their scope, because include takes scope into account.
Let's say your partials/userValues.php file looks something like this...
<p><?=$var1?></p>
<p><?=$var2?></p>
<p><?=$var3?></p>
If you want to include it from your function you can. You can also use output buffering with functions like ob_start() and ob_get_clean() to write the output into a buffer and return that from the function instead of just printing directly to standard out.
function foo($var1, $var2, $var3) {
ob_start(); // start the output buffer first
include 'partials/userValues.php'; // include inherits the variable scope
$output = ob_get_clean(); // close the buffer and store it in $output
return $output; // return it to the caller
}
Related
To include raw JavaScript files into my pages, i've ended up using:
function include_js($jsfile, $basepath = JSPATH){
echo '<script type="text/javascript">';
include($basepath . $jsfile);
echo '</script>';
}
Works fine, and the PHP code inside these JS files is still executing fine, no problem here.
But here is some pseudo code of what i used before:
<script>
var hello = '<?php echo $id; ?>';
</script>
So, here's the problem:
Before, the PHP code used inside my JavaScript files was executed in the same context as the page's one.
Now, it's executed in the context of the include_js() function.
Thus, i don't have access to any of my page's variables anymore. I could fix it with a global $id;, but that was pseudo-code.
Actually, i have NO idea what variables i'll need to have access to.
Any idea how to solve that problem? If you have a better solution than what i'm actually doing inside include_js() to achieve the same goal without the problem i'm talking about, that would be as much appreciated!
You could import all global variables (but Superglobals) into the local scope of the function where you do the include. I don't think it's really a good solution (as it's a hammer) but as you write in your question you don't know which variables are used, so you could localize them like:
$varname = $GLOBALS['varname'];
As an alternative you could inspect the JS file and/or provide the list of variables for a file and add it to the include function as an array. See another answer for some code example.
You could also first pre-include (and throw away) the js file, gather the warnings about undefined variables, import them and then include for real. Some more include/discard/return/variable related chunks of code.
You can use global variables, but a more robust way is to write your own "constant databases". Something like:
class ConstantDB{
public static function set($key, $value){
}
public static function get($key){
}
}
It's just very convenient in many cases. For your particular situation, then you can use
ConstantDB::set("my_id", $id);
and inside the include_js, you can use
ConstantDB::get("my_id");
I have tested the following and it doesn't work. Is there a similar way of achieving this?
A compiling class which formulates a template:
private function include_header () {
function _metadata () {
// Metadata compiler
return $metadata;
}
include (path . "header.php");
}
header.php
<html>
<head>
<?php
_metadata ();
?>
<title>Hello Stackoverflow!</title>
</head>
<body>
...
The _metadata (); function is only available within the include_header (); function - nowhere else in the class. I don't want to have to write $this->_metadata (); in the template file only _metadata ();. Is that achievable?
Alternatively one could create an external file, for example functions.php which has the underscore functions specifically for the template - but I'd much rather see if the original query is possible.
Thank you in advance.
From the manual:
All functions and classes in PHP have the global scope - they can be called outside a function even if they were defined inside and vice versa.
So, essentially, you can't do what you're trying to do. _metadata will always be a global function if it is defined with the function _metadata() { syntax. The normal function syntax only supports global functions.
However, PHP 5.3 introduces something called "anonymous functions". These can be assigned to a variable. Since variables can be scoped to a function scope (they are only global if you explicitly say so), you can limit them in this way.
For instance:
$_metadata = function() {
// Metadata compiler
return $metadata;
};
This could then be called in header.php with:
<?php $_metadata(); ?>
Note that this is less stable: it is, for instance, possible to redefine the variable to be a different anonymous function – or indeed not a function at all. The safest solution, ultimately, is to use a templating language that solves these issues for you. If not, you can either accept that you'll have to use global functions or anonymous functions.
You can't define nested function in PHP. I mean, you can, but there's no purpose since they'll have a global scope and therefore they will be callable from any point of the script.
But you actually don't need to define a _metadata() function, you can just execute all the function logic inside include_header() and then store everything in the variable $metadata, which will be printed in the include with a simple <?php echo $metadata; ?>.
If you really need to define a function you can use the function create_function() or (just for PHP > 5.3) an anonymous function. Since they will be encapsulated inside a variable, which has a function scope, they won't be available outside.
I'm having a bit of trouble understanding includes and function scopes in PHP, and a bit of Googling hasn't provided successful results. But here is the problem:
This does not work:
function include_a(){
// Just imagine some complicated code
if(isset($_SESSION['language'])){
include 'left_side2.php';
} else {
include 'left_side.php';
}
// More complicated code to determine which file to include
}
function b() {
include_a();
print_r($lang); // Will say that $lang is undefined
}
So essentially, there is an array called $lang in left_side.php and left_side2.php. I want to access it inside b(), but the code setup above will say that $lang is undefined. However, when I copy and paste the exact code in include_a() at the very beginning of b(), it will work fine. But as you can imagine, I do not wish to copy and paste the code in every function that I need it.
How can I alleviate this scope issue and what am I doing wrong?
If the array $lang gets defined inside the include_a() function, it is scoped to that function only, even if that function is called inside b(). To access $lang inside b() you need to call it globally.
This happens because you include 'left_side2.php'; inside the include_a() function. If there are several variables defined inside the includes and you want them to be at global scope, then you will need to define them as such.
Inside the left_side.php, define them as:
$GLOBALS['lang'] = whatever...;
Then in the function that calls them, try this:
function b() {
include_a();
print_r($GLOBALS['lang']); // Now $lang should be known.
}
It is considered 'bad practice' to use globals where you don't have to (not a consideration I subscribe to, but generally accepted). The better practice is to pass by reference by adding an ampersand in front of the passed variable so you can edit the value.
So inside left_side or left_side2 you would have:
b($lang);
and b would be:
function b(&$lang){...}
For further definitions on variable scopes check this out
can I put a function in PHP inside a if structure? like this:
<?php
if(true){
function HelloWorld(){
echo "Hello World!!!";
}
HelloWorld();
}
?>
because I have tried and it works, but I don't know if it is correct or not. Thanks
This is perfectly legal - it simply defines the function within the if statement block. That said, quite why you'd want to do this is somewhat of a mystery.
It's also worth noting that this function will be available in the global scope (i.e.: outside of the if statement block), as...
All functions and classes in PHP have
the global scope - they can be called
outside a function even if they were
defined inside and vice versa.
See the PHP User-defined functions manual page for more information.
As middaparka says, this is perfectly legal, but in terms of using it, you might want to check if a function exists before declaring it:
if (!function_exists("foo"))
{
function foo()
{
return "bar";
}
}
function_exists documentation
It looks a bit strange, but yes it's legal
As of PHP 5.3 if you need a function with a limited scope (say for a callback) you can use anonymous functions / closures
I wanted to add an answer here, because there's a caveat that isn't addressed in the other answers.
Based on my testing in 5.3, it appears that functions that are defined inside if structures are defined at runtime, rather than at compile time like other functions.
For example, outside a conditional block, this:
foo();
function foo(){
echo 'foo!';
}
works fine because the function is defined at compile time, and executed at runtime. But calling the function before defining it while inside a condition block:
if(1){
foo(); // Call to undefined function!
function foo(){
echo 'foo!';
}
}
Will produce a call to undefined function error, at least as of version 5.3.
But defining the function in an if block before calling it is valid:
if(1){
function foo(){
echo 'foo!';
}
foo(); // No errors, since function is defined!
}
So there is a major gotcha to be aware of when defining functions inside a conditional: the function must be defined in the code before calling the function, since conditional functions don't seem to get defined at compile time.
The OP also asked about performance. If the conditional function is defined at runtime instead of compile time like most other functions, then this function will not benefit from performance boosters like OpCode caching, which depending on the circumstances, could slow down your application. For example, if your master php file looked like:
if($IsLoggedIn){
// include files/functions and bootstrap here...
}
Then the entire application might not benefit from OpCode caching at all.
Basically yes, according to the manual:
Any valid PHP code may appear inside a
function, even other functions and
class definitions.
Personally I haven't had a situation in which I'd actually do such a thing. Most of the time it would be easier to group your functions on a place where it actually can be found! ;-)
I have a function that retrieves some data from the database, formats it as HTML and then stores this HTML into a variable, $output. The problem is that $output cannot be echoed on the screen now, only later, after other functions run. Also this data must be retrieved at this stage, not later.
So how can I call this $output variable in another function, after output to the screen has started?
You could define $output in the main script, and import it into a function:
function output()
{
global $output;
This will probably work for your situation at hand. However, it is considered bad practice to use the global variable space with stuff like this, and rightly so. (Believe me, I've done it for years. :)
There are some other approaches that are better for long-term code quality and maintainability.
Global config array
You could either keep one global array for all global settings. Do this somewhere in your main script:
$config = array();
$config["output"] = "<html>.......</htmL>";
$config["user_language"] = "en";
.....
you import the configuration array into the function like so:
function output()
{ global $config;
echo $config["output"];
Registry pattern
if you want to do some reading, you could use something more advanced like the Registry Pattern. The snippet shown here looks a nice example for a registry. The Zend Framework also has a class for this.
But things like a Registry are really, really advanced, and probably not necessary for you at this point. I would suggest using one central config array. Should the need for something more complex arise, the config array is easy to find and replace.
Context: Are global variables in PHP considered bad practice?
welcome to using returns, and passing parameters:
DO NOT USE global , it breaks encapsulation, one of the cornerstones of object oriented programming, and can lead to incredibly hard to maintain code.
<?php
function doSomethingInDb(){
$value = db_result(); //something from the database, this is psuedo code
return $value
}
function displaySomethingFromDb($input){
echo($input); //or some other way of displaying
}
//calulate results
$output = doSomethinginDb();
//do other stuff...
//output the result when you need it...
displaySomethingFromDb($output);
You have to pass the variable via a function argument, or define it as global inside the function.
$output = '<p>macilaci</p>';
function doesathing($output)
{
echo $output;
}
OR
function doesathing()
{
global $output;
echo $output;
}
don't put the data in a variable inside the function which retrieves it.
function retrieve(...)
{
... fetch from db
return $rv;
}
function other() {...}
function still($data)
{
...
echo $data;
}
$output = retrieve(...);
other();
still($output);
Rather than just putting this snippet into a global variable, IMHO a better solution is to use a templating system to construct the elements of the page.
NB I'm not suggesting you immediately rush out and start downloading Smarty - although there are benefits and drawbacks to completely seperating logic and presentation, there are only benefits in taking a modular approach to your screen layout.
C.
Put the following line at the start of the function that defines $output:
global $output;
Put the same line at the start of any function that will make use of it.
(This will not work, or will interfere with other variables, if there is already a variable called $output in the global scope.)
Use Session
For example:
session_start();
$query = '...........';
$result = mysql_query($query);
$_SESSION['mysqlResult'] = $result;
Now you can use it from any page at any time by simply calling like this
$myresult = $_SESSION['mysqlResult'];