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'];
Related
I am building a PHP MVC framework like Ruby on Rails but with PHP for learning. The link just in case you want to see it is https://github.com/carlinoo/vinum
I was trying to see the source code of CakePHP as it is very similar to mine. When in aa action in a controller, after the logic of that action/method, it calls the view, a different file that has access to those variables. I cant seem to understand how that works.
How does it call the view after the logic is finished? In CakePHP there’s something called autoRender that if set to true, it renders the appropriate view. How can you do that without calling a function to render the view?
Also, I have a variable scope problem. Let me explain:
function func1() {
$var = 1;
render();
}
function render() {
require_once(‘file.php’);
}
// This is file.php
<?php
echo $var;
?>
$var one does not exist because of the scope, and i don’t want to declare the variables as global. How do big PHP Frameworks do this? And how does the autoRender actually work? Thank you
This is the "easy" way
function func1() {
$var = 1;
render(‘file.php’, get_defined_vars());
}
function render($file, $vars = []) {
extract($vars);
require $file; //pass the filename in for reuse
}
But it's really messy, and prone to variable name collisions.
This function returns a multidimensional array containing a list of all defined variables, be them environment, server or user-defined variables, within the scope that get_defined_vars() is called.
http://php.net/manual/en/function.get-defined-vars.php
Import variables from an array into the current symbol table.
http://php.net/manual/en/function.extract.php
I would manually build an array of variables, pass that to render($vars) and then use extract().
function func1() {
$vars = ['var1' => 1];
render(‘file.php’, $vars);
}
Also I would use require instead of require_once otherwise if you need to render the same template multiple times it wont work, think like in the case of a post or something you can loop on and call render multiple times. For example
you may have a "controller" named posts.php
render('header.php');
render('menu.php');
foreach($posts as $post){
render('post.php', $post);
}
render('footer.php');
The main Idea behind a template is to eliminate structural PHP mixed into the HTML. So you would want, smaller chunks of HTML that you can reuse multiple times. And mostly keep it to echoing variables in the tempate/view
Lastly, I would take what I put above as "theoretical" code, I can't really test this very well, but that's the basic concept.
UPDATE
Here is a quick Psudo-ish Code example of what CakePHP does ( obviously its way more complex then i can do in an answer on here ).
Its mainly the difference between using procedural and object oriented coding.
class Controller{
protected $data;
public function index(){
$this->color = 'pink';
$this->render('view.php');
}
///magic method
public function __set( $key, $value){
$this->data[$key] = $value;
}
/*
you can do the same thing with a normal method
public function set( $key, $value){
$this->data[$key] = $value;
}
but instead of doign $this->color = 'pink';
you would do $this->set('color', 'pink');
*/
public function render($file){
/*
obviously I can easily access $this->data['color']
from within the scope of the same class.
*/
extract($this->data);
include $file;
/*
or any number of other things
like
$contents = file_get_contents($file);
foreach( $this->data as $key => $value )
$contents = str_replace('{'.$key.'}', value , $contents);
echo $contents;
for tags like {color} etc.
*/
}
}
Right here is every method they are using.
https://api.cakephp.org/3.5/class-Cake.Controller.Controller.html
And here is the source code for their controller,
https://api.cakephp.org/3.5/source-class-Cake.Controller.Controller.html#583-622
Honestly I wouldn't recommend using the magic metods like __set __get etc. because it Makes the code
harder to read
harder to maintain
more prone to error
less efficient, performance wise.
For example
$this->set('data', 'foo');
Is safe, but using
$this->data = 'foo';
Will wipe out that data array property, because in my example the data gets put into a class property named data as an array, so calling $this->data = foo; accesses the already existing property and overwrites it. Which then means you have to do all kinds of checks and other things to make sure nothing gets overwritten, and anytime you add any properties you have to deal with that kind of stuff. And if you miss something you may not find it for months and then one day, you set data in a controller and it all falls apart.
For reference.
http://php.net/manual/en/language.oop5.magic.php
Anyway
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
}
There is like a million Template Engine for PHP (Blade, Twig, Smarty, Mustache, ...), and i just hate the idea of creating a new syntax and compiler to write PHP inside HTML! I think it's just not smart (but this isn't what i am here to discuss :) ), what is wrong with writing PHP+HTML the usual way - not for logic - you know, all the variables and loops and defines you wanna use without this {{% %}} or that {:: ::} ! At least for performance sake!
Now, i am using Laravel these days , and it's awesome; it offers (besides Blade and any other 3rd party engine) a plain PHP templates system that uses ob_start/include/ob_get_clean and eval. I was very happy to know that i can avoid learning a new syntax to write PHP inside HTML.
Here is what i am suggesting; what about instead of using ob_* functions with include, we use Closures ? Here is a simple class i put together just to make a point:
class Templates{
static public $templates = array();
static public function create($name, $code){
self::$templates[$name] = $code;
}
static public function run($name, $data){
if(!isset(self::$templates[$name]) || !is_callable(self::$templates[$name])) return false;
return call_user_func(self::$templates[$name], $data);
}
}
And here is how to use it:
Templates::create('test', function($data){
return 'Hi '.$data['name'].' ! ';
});
for($i =0; $i < 10; $i++){
print Templates::run('test', array('name' => 'Jhon'));
}
I think this way is much better, since i wont need to do any output buffering or use eval. And to "separate concerns" here, we can put the Templates::create code in a separate file to keep things clean, in fact this way things can become more simple and elegant; we can make another method to load the template file:
static public function load($name){
self::create($name, include($name.'.php'));
}
And the content of the template file will be as simple as this:
return function($data){
return 'Hi '.$data['name'].' ! ';
};
What do you think of this ? Is there any problems with the approach or the performance of such use of Closures ?
I do not think there are any problems besides that if you put all closure functions into array, that would possibly mean that functions are kinda doing basically the same stuff.
What I mean by this:
In your example you have your functions accepting only 1 parameter. So, not to create a mess all functions you create would accept the same set of parameters and return the same type of data.
However when declared apart, functions may be supposed to do something different and unique.
Why such a solution is suitable: when using some engines, there may be a lot of different functions declared already. To resolve the conflict, they can be "hidden" inside arrays.
Also, some people even say that anonymous functions can be generally better in case of performance. But we have to test that first: to call a function you:
Call a static function run
Check a function for existence
Check a function for callability
And then use call_user_func which returns the return of your function. So, 3x return.
Update
My recomendations for you code:
Make all possible checks only when creating a function. That will greatly buff performance.
static public function create($name, $code){
if (!isset(self::$templates[$name])){
if (is_callable($code)){
self::$templates[$name] = $code ;
} else {
//func is not callable, Throw an exception.
}
} else {
//function already exists. Throw an exception.
}
}
That way you just can have 2x increase in performance:
static public function run($name, $data){
if (isset(self::$templates[$name])){
self::$templates[$name]($data); //Just make a straight call
} else {
//throw new Exception(0, "The func is not defined") ;
}
}
We use instantiate and put system critical objects in $GLOBALS for easy access from anywhere (e.g. DB, Cache, User, etc.).
We use $GLOBALS so much that it would (yes, really) drop the amount of code quite a bit if I could reference it like $G = &$GLOBALS for a shorthand call.
The problem is that, per my experience and several hours of Googling, I have not found any construct in PHP which allows you to 'flag' a var as global, making $GLOBALS first class, and everything else second class.
Am I missing something? Is this possible?
<?php
function &G($name) {
if(func_num_args() > 1) {
$GLOBALS[$name] = func_get_arg(1);
}
return $GLOBALS[$name];
}
G('test', 'hey');
echo G('test'); // outputs hey
echo $test; // outputs hey
$b =& G('test');
$b = 'hello';
echo G('test'); // outputs hello
echo $test; // outputs hello
Instead of putting everything into $GLOBALS you might want to take a look into the registry concept that is widespread in the php world.
However, having many global variables/objects is a sign of bad design and high coupling. Using something like $G guarantees spaghetti code and a soon-to-come maintenance nightmare. Who cares if you can drop the amount of code by a few characters?
No, but you can use a little trick. Create a global function by the same name as your global var, and have it return the global instance. Eg.:
function db() {
return $GLOBALS['db'];
}
You can now write your code as:
...
$stuffs = db()->query("select * from stuff");
...
You may recognise this as a variant over the singleton pattern, but a syntactically much more pleasant one.
Others have mentioned it, but you should also consider not using global objects in the first place. I generally prefer to pass objects in to there where it's needed (dependency injection). I'm not overly found of the registry pattern though.
global $variable; //?
In addition to the registry concept Middus points out, there are several approaches and concepts around this, some of which you can find in the answers to this question:
In a PHP project, how do you organize and access your helper objects?
I am writing a basic templating class for my own project. The basic usage is this:
$template = new Template('template_file.php');
$template->assignVariable('pageTitle', 'Home page');
$template->render();
Contents of 'template_file.php':
<?php print $pageTitle; ?>
This is what template class does step by step:
Stores variables in a private array when assignVariable method is called
When render method is called, extracts stored variables, includes template file in a ob_start() and ob_end_clean() block. Stores output in a variable with ob_get_contents() and then prints stored output.
I know this is a very simple templating class but works as expected. The question is should I delegate the including the template file to another class? I had this question when I was writing the unit tests for this class. I thought that file system interaction should be encapsulated. What do you think? If you think that it should not, how can I mock including a file in my tests?
Maybe I just pass the contents of the template file to the class like this:
$templateContent = file_get_contents('template_file.php');
$template = new Template($templateContent);
...
Edit: I decided to encapsulate the input process of template class for the sake of writing better unit tests and encapsulation. But as johannes pointed out, I needed to use eval() for that purpose which seemed not right. Johannes pointed me to the direction of stream wrappers for mocking the including in unit tests. But that inspired a new idea on me. Here is what I am going to do; I will continue to use include() in my template class but this time with stream wrappers. I will pass protocol handler to my template class while initializing it. This way I can create my own stream wrappers for fetching template data from database or using a local variable. Here are the examples:
$template = new Template('file://template_file.php');
stream_wrapper_register('database', 'My_Database_Stream');
$template = new Template('database://templates/3'); // templates table, row id 3
stream_wrapper_register('var', 'My_Var_Stream');
$myTemplate = '<?php print "Hello world!"; ?>';
$template = new Template('var://myTemplate');
I have already implement custom stream wrapper for local variables. Here it is:
class My_Var
{
protected $position;
protected $variable;
function stream_open($path, $mode, $options, &$openedPath) {
$url = parse_url($path);
global $$url['host'];
$this->variable = $$url['host'];
$this->position = 0;
return true;
}
public function stream_read($count) {
$ret = substr($this->variable, $this->position, $count);
$this->position = strlen($ret);
return $ret;
}
public function stream_eof() {
return $this->position >= strlen($this->variable);
}
}
stream_wrapper_register('var', 'My_Var');
$myvar = '<?php print "mert"; ?>';
include 'var://myvar';
exit;
I always liked the approach of this fellow:
http://www.massassi.com/php/articles/template_engines/
This approach takes advantage of the fact that PHP has started as a template engine. (The author also notes that it is silly to write a bloated template engine in PHP, when it is in fact itself a templating engine.) It might not really answer your question directly, but maybe it helps you.
By passing the contents using file_get_contents() and such you have to use eval() for execution which is bad in multiple ways. One of the most relevant here is that an opcode cache can't cache the file then. Doing an include('template_file.php'); let's APC or others cache the compiled script.
Irrespective of the evils of eval vs using a include, to answer your question, I'd have to agree and use a separate class to encapsulate the I/O aspect of your solution.
Whilst this might seem like overkill (as it will be in most instances), this is probably the only sane way to provide the isolation of control/dependency injection that you're after.
The question is should I delegate the including the template file to another class?
The question is, why not?