This is probably considered a really silly question, but I'm in the process of putting together a simple template system for a website and am trying to keep track of my variable usage and keep everything neat and tidy.
Can you tell me if there is any advantage/disadvantage to the following methods:
simple var:
$tpl_title = 'my title'
$tpl_desc = 'my text'
array:
$tpl['title'] = 'my title'
$tpl['desc'] = 'my text'
Object:
$tpl->title = 'my title'
$tpl->desc = 'my text'
I like the object method the best as it looks clean when echo'd within html as opposed to arrays and afaik it can be used in an array-like way? However, what I want to know is whether using objects in this way is considered bad practice or introduces unneccesary overheads?
In ideal scenarios every variable should belong to an object, other than the variables local to methods for temp purposes. However we don't live in an ideal world and specially our programming languages are far from it. Based on what the situation is, choose the best way to go about it to make your life easier. If you are using things for templates, generally you keep all the data in an array and extract the array to get stand alone variables.
So yeah, the object method is the nicest, try to make it happen as much as you can without spending crazy amounts of time in doing it.
Also if you love objects and want to have the neat -> way of doing it, you can do
$object = (object)$array;
That would convert your array to an object.
Hope that helps.
I would consider it unnecessary overhead. Doing what you are talking about in an object-oriented way only means that inside your class you will have done nothing more than create a bunch of variables, just as you specified in your first example.
The array is the best way to go in my opinion. You are only using one variable, and you can also integrate it into your Class. So, instead of $tpl->title, you may have $tpl->text['title'].
Arrays
I would suggest on the backend part, keep everything stored in an array. This allows you to have only one variable to keep track of, and once you pass it to the frontend, you can extract() the array, to convert them into simple variables.
Syntax
Using extract() simplifies the syntax on the FrontEnd, which means you will only always have $varibles in the template.
On the backend you would set
$array['title'];
Which once extracted would in the template be
$title;
Example of a backend function
protected function fetch($template, $data = null)
{
if (!$this->isTemplate($template)) {
throw new Exception("Template file $this->_templatePath$template not found");
}
ob_start();
if (is_array($data)) {
extract($data, EXTR_SKIP);
}
require $this->_templatePath . $template . EXT;
return ob_get_clean();
}
In the end they are the same, It depends on the preference, although I would use arrays or objects because you can group variables in there, so you have things better sorted out.
Despite the objects method works I think it's not the natural intended use for it.
So I would say arrays!
Also, there are tons of php native functions you can use with arrays, like array_map() or array_filter() array sortings and etc etc...
In my opinion the cleanest way to set it up is in array like this:
$tpl = array (
'title' => 'my title',
'desc' => 'my text'
);
You can combine it with Zane's answer also.
All the best!
$tpl = array (
'title' => 'my title',
'desc' => 'my text'
);
Like Goran said, with the bonus that you could store these arrays in an ini file later and extract them as needed with parse_ini_file
Could be important if you want to permit users to write to their own ini file.
arrays and objects are useful in case if you want to reset bulk of variable data after use it.
you can simply unset the array or destroy the object instead of unset range of variables use in a code.
Other than this arrays and objects have more symmetry in code and explanatory than normal variables
Related
I think this is quite interesting!!! :).
What I've got?
In the application that I'm using on some level in some objects (doesn't really matter) I get an array, for example:
$array = array(
'argument_label' => 'value_label',
'argument_name' => 'value_name',
'argument_id' => 'value_id'
)
I don't have any impact on how and when this array is created. Next, I've got a method:
public function arrayArgument($array) {
$label = isset($array['argument_label']) ? $array['argument_label'] : 'default_label';
$name = isset($array['argument_name']) ? $array['argument_name'] : 'default_name';
$id = isset($array['argument_id']) ? $array['argument_id'] : 'default_id';
// Do something
return 'something';
}
I really hate it. There is no way of proper documentation for the method arguments (as PHPDocumentator work not so well with arrays), and those issets are driving me crazy. Additionally it is a nightmare for someone who will work with this code in the future, when I will already be a "retired nerd".
What I want?
I want to have a function like that:
public function notArrayArgument(
$id='default_id',
$label='default_label',
$name='default_name'
) {
// Do something
return 'something';
}
What I can do?
When I get array, I can change some code, and make my own method run. So I need some kind of solution to get from here:
$array = array(
'argument_label' => 'value_label',
'argument_name' => 'value_name',
'argument_id' => 'value_id'
)
To here:
notArrayArgument('value_id', 'value_label', 'value_name');
Or here:
notArrayArgument($array['argument_id'], $array['argument_label'], $array['argument_name']);
What are the problems?
This is not template like. The number of variables is always different, the names are always different, and sometimes some of them are passed, sometimes not.
It should work really fast...
Calling the method arguments in the right order. Array can be sorted, not sorted or random sorted, while the arguments inside method are always in the same order. The array should be reordered to match the method arguments order, and after that the method should be called.
What I came with?
I've got an idea using reflectionClass. I can check the names of method arguments, get them in order, reorder the array and try to call this method. But this is quite resource eating solution, as reflectionClass is not so fast I think.
Solution using extract? This would be great. But after extract, I need to use exact variables names in code. And I don't know them as every time they are different, and I need an universal approach.
NEW (thx to comment): call_user_func_array(). It is great, but it only works with indexed arrays, so this will be the last but not least step of the possible solution. As the order of arguments is still unknown...
Does this problem have a nice semantic, pragmatic solution?
I read my question once more, and I hope it is clear to understand. If not, please post a comment and I will do my best to describe the problem better.
Kudos for thinking about the maintainer, but I'd argue simplicity is just as important as nice semantics and pragmatism. Consider this: if you had to ask how to write such a pattern, what are the chances that it will be obvious to the reader? I'd much rather come across code where I can just think "Yep, that's clear" than "Oh cool that's a really intricate and clever way of setting array defaults".
With this in mind, it seems to me that an array is being used in a situation more suited to a class. You have an id, a label and a name, which surely represents an entity - exactly what classes are for! Classes make it easy to set defaults and provide PHPDoc on each of their properties. You could have a constructor that simply takes one of your existing arrays and array_merge()s it with an array of defaults. For the reverse conversion, conveniently, casting an object to an array in PHP results in an associative array of its properties.
Try to use classes as George Brighton mentioned.
If you can't for some legacy or library constraint, you will have to use reflection. Don't worry too much about the performance of reflection classes, a lot of frameworks use them to do the request routing.
You can use a function like:
function arrayArgument($object, $method, $array)
{
$arguments = [];
$reflectionMethod = new ReflectionMethod(get_class($object), $method);
foreach ($reflectionMethod->getParameters() as $parameter)
{
$arguments[] = isset($array[$parameter->name]) ? $array[$parameter->name] : $parameter->getDefaultValue();
}
call_user_func_array(array($object, $method), $arguments);
}
So you can do
$instance = new MyClass();
arrayArgument($instance, 'notArrayArgument', ['name' => 'myname']);
I'm just looking for a MORE eloquent way of defining an array of empty error strings for a mail form then this...
$err = array('NAME'=>'', 'EMAIL'=>'', 'ADDR'=>'', 'CS_LOC'=>'', 'ZIP'=>'','PHONE'=>'', 'COMMENTS'=>'', 'FILE'=> '');
Since I have to flush these occasionally anyway, certainly anytime the form posts, I've already set up a function like the below which I call as needed, like this.
function clearFormErrors(&$ary) { // fill error array with empty strings
$keys = array_keys($ary);
$filled = array_fill_keys($keys, '');
}
Not a big deal [EDIT]:, but since I'm going to call this anyway, it would be nice if there were some nice 'wishlist' way I could just define the array **KEYS when I declare it**, like this...
$err = array('NAME', 'EMAIL, 'ADDR', 'CS_LOC, 'ZIP,'PHONE', 'COMMENTS, 'FILE');
Of course the above does NOT have that desired effect. I'm just curious if there is some simple directive or method that I've missed in the PHP docs that would just let me define the keys (with or without some default type). I'm sure there is a more complicated function that could be created to build a new array using the keys (now values) from my above 'wishlist' array, but it sounds like it wouldn't make the code any shorter or more 'eloquent', right?
If you have array of keys, array_fill_keys is the most elegant way to "reset" the array. The other way that makes sense is array_map, but for your simple task it seems like a little overhead.
I am new to php. I was wondering how I could declare a static array in php. Here is what I would do in C. How is the corresponding php code for it?
char a[][] = { (1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3) };
From what I read it has to be something like this -
$a = array( 1 => array(1,1), 2 => array(1,2), ... );
Is this correct? If so it sucks :) I hope I am wrong.
Thanks,
- Pav
You've already found the way to do it natively.
Another option would be to declare your data as JSON (a very concise and human-friendly format). This could be either in a separate file bundled with your app, or directly in your code in a string. Then parse the JSON at runtime. Since PHP isn't exactly known for speed, this may or may not make your noticeably app slower to start.
you have it already figured out in your question.
One thing I would add is that you do not need to explicitly define the keys if you are intending to use a zero based array, this is assumed and can be done like so...
$a = array(array(1,1),array(1,2), ... );
You can also use what is called associative arrays which use string keys and you define them the same way you do in your example, except use strings instead of numbers...
$ass_array = array( 'array_1' => array(1,1), 'array_2' => array(1,2), ... );
you would then call your associative array like this...
$ass_array['array_1'];
Also, if you want to append single items to an array (for example in a loop to load an array)...
$ass_array[] = $item;
Further to jondavidjohn's anwser, you could just write a quick script to grab your list of values and generate the array statement for you.
No need to care how verbose the syntax is then. If the task is long and repetitious enough to care, don't do it by hand. :)
The reason I am asking this question is because I have landed my first real (yes, a paid office job - no more volunteering!) Web Development job about two months ago. I have a couple of associates in computer information systems (web development and programming). But as many of you know, what you learn in college and what you need in the job site can be very different and much more. I am definitely learning from my job - I recreated the entire framework we use from scratch in a MVC architecture - first time doing anything related to design patterns.
I was wondering what you would recommend as the best way to pass/return values around in OO PHP? Right now I have not implement any sort of standard, but I would like to create one before the size of the framework increases any more. I return arrays when more than 1 value needs to get return, and sometimes pass arrays or have multiple parameters. Is arrays the best way or is there a more efficient method, such as json? I like the idea of arrays in that to pass more values or less, you just need to change the array and not the function definition itself.
Thank you all, just trying to become a better developer.
EDIT: I'm sorry all, I thought I had accepted an answer for this question. My bad, very, very bad.
How often do you run across a situation where you actually need multiple return values? I can't imagine it's that often.
And I don't mean a scenario where you are returning something that's expected to be an enumerable data collection of some sort (i.e., a query result), but where the returned array has no other meaning that to just hold two-or-more values.
One technique the PHP library itself uses is reference parameter, such as with preg_match(). The function itself returns a single value, a boolean, but optionally uses the supplied 3rd parameter to store the matched data. This is, in essence, a "second return value".
Definitely don't use a data interchange format like JSON. the purpose of these formats is to move data between disparate systems in an expected, parse-able way. In a single PHP execution you don't need that.
You can return anything you want: a single value, an array or a reference (depending on the function needs). Just be consistent.
But please don't use JSON internally. It just produces unnecessary overhead.
I also use arrays for returning multiple values, but in practice it doesn't happen very often. If it does, it's generally a sensible grouping of data, such as returning array('x'=>10,'y'=>10) from a function called getCoordinates(). If you find yourself doing lots of processing and returning wads of data in arrays from a lot of functions, there's probably some refactoring that can be done to put the work into smaller units.
That being said, you mentioned:
I like the idea of arrays in that to pass more values or less, you just need to change the array and not the function definition itself.
In that regard, another technique you might be interested in is using functions with variable numbers of arguments. It is perfectly acceptable to declare a function with no parameters:
function stuff() {
//do some stuff
}
but call it with all the parameters you care to give it:
$x = stuff($var1, $var2, $var3, $var4);
By using func_get_args(), func_get_arg() (singular) and func_num_args() you can easily find/loop all the parameters that were passed. This works very well if you don't have specific parameters in mind, say for instance a sum() function:
function sum()
{
$out = 0;
for($i = 0; $i < $c = func_num_args(); $i++) {
$out += func_get_arg($i);
}
return $out;
}
//echoes 35
echo sum(10,10,15);
Food for thought, maybe you'll find it useful.
The only thing I'm careful to avoid passing/returning arrays where the keys have "special" meaning. Example:
<?php
// Bad. Don't pass around arrays with 'special' keys
$personArray = array("eyeColor"=>"blue", "height"=>198, "weight"=>103, ...);
?>
Code that uses an array like this is harder to refactor and debug. This type of structure is better represented as an object.
<?php
Interface Person {
/**
* #return string Color Name
*/
public function getEyeColor();
...
}
?>
This interface provides a contract that the consuming code can rely on.
Other than that I can't think of any reason to limit yourself.
Note: to be clear, associative arrays are great for list data. like:
<?php
// Good array
$usStates = array("AL"=>"ALABAMA", "AK"="ALASKA", ... );
?>
DISCLAIMER:
Please read carefully as this is NOT a question about storing arrays in constants or simple eval() or serialize() techniques. This IS a question primarily about how constants work in PHP and why the constant() function is not working to convert a constant name into a constant value. Thanks.
BACKGROUND:
For various reasons, I started out with a flat config file for a homebrewed LAMP(PHP) CMS (in private development). Looking back this may have been misguided, and I have transitioned my variable storage into a DB table. However, the bulk of the code still depends on the CONSTs, so I use eval("define(A, B...);") to load the DB values A and B into constants. This part works fine. But it gets a bit more complicated.
PROBLEM:
The problem I'm having now is with constants in arrays (NB. NOT arrays in constants). I have a big, GLOBAL array called defaults that contains config settings in the format shown below.
Initially, I declare: <?php define('THIS_IS_A_CONSTANT', 'abcdefg'); ?> (And THIS WORKS...)
Next, I define $GLOBALS['defaults'] as the following nested array:
Array
(
'var_name' => Array
(
'display' => THIS_IS_A_CONSTANT,
'value' => 12,
'type' => 'int',
'params' => Array ( ... )
),
...
Lots more variables...
...
)
To prevent the client (who has file system access but no direct DB access but can change certain values, including most constants, via the CMS's administrative backend) from mucking up this array structure, I serialize the array structure and store that string in the DB. On each page request, I first define all the constants (stored in the DB) using the eval(define(A,B...)), then I unserialize the array above (which was serialized and stored in the DB). However, no matter what I try I cannot get the values at $GLOBALS['defaults']['var_name']['display'] to be recognized as the values that the constants contain. Instead, the constant name shows up and NOT the constant value (in other words, my output contains THIS_IS_A_CONSTANT instead of 'abcdefg'). Very frustrating, right?
I've tried something like the following (where $arr contains the unserialized array that I fetch from the DB):
foreach ($arr as $item => $contents) {
$display = isset($contents['display']) ? $contents['display'] : 1;
$value = constant("$display");
// This doesn't work, though it seems like it should
$contents['display'] = $value;
// Neither does this, no matter how much I juggle the quotation marks and backslashes
eval("\$contents['display'] = constant(\"$value\");");
// or this ...
eval("\$contents['display'] = $value;");
// or this ...
eval("\$contents['display'] = \$value;");
// or a number of other things...
}
$GLOBALS['defaults'] = $arr;
QUESTIONS:
Has anyone dealt with this kind of situation before? Can anyone advise me how to force my constants to be recognized as CONSTANTS and not strings. Do I need to serialize my array differently? Or maybe process the unserialized array differently (after retrieving it from the DB)? Is these some combination of eval() and constant() that will allow me to do this? Why are the constants within my array behaving badly while the constants I define normally are working without problem? Any help at all would be greatly appreciated, as I've been puzzling over this for a few days now and haven't come to any solutions.
All the best, Dakota.
Although eval does have its uses, this is not one of those cases. You have no idea what is being submitted to the eval at run time - and by the sounds of things you are storing something which you are then treating as code in a user-data storage location.
If the constant was defined before the array was declared then the serialized version would contain the value instead of the label. I can only assume that the value may differ depending on the context at run-time.
I would suggest that a better solution would be to roll your own macro language in PHP, e.g. something like:
<?php
global $defs;
$defs=array(
'THIS_IS_A_CONSTANT' => 'abcdefg',
'SO_IS_THIS' => 23
);
// for inline constants
foreach ($defs as $label =>$val) {
define($label, $key);
}
replacer($defs,true);
function replacer($in, $init=false;)
{
static $defs;
static $vals;
if ($init) {
$defs=array_keys($in);
$vals=array_values($in);
return count($in);
}
return str_replace($defs, $vals, $in);
// you might want to use preg_replace() with a pattern based on $defs for a neater solution
}
function fix_var(&$in)
{
if (is_array($in)) {
foreach ($in as $key=>$dummy) {
fix_var($in[$key]);
}
} else {
$in=replacer($in);
}
}
?>
C.
First, why are you evaling? From what you are saying you want the value of $GLOBALS['defaults']['var_name']['display'] to be the value of the constant THIS_IS_A_CONSTANT. You have de-serialized the string from your database and shoved in in $GLOBALS['defaults'] and the string stored the value as the constant name, not the value of the constant.
Have you tried:
<?php
define('THIS_IS_A_CONSTANT', 'abcdefg');
$value = constant($GLOBALS['defaults']['var_name']['display']);
//$value should now be abcdefg not THIS_IS_A_CONSTANT
$GLOBALS['defaults']['var_name']['display'] = $value;
?>
If "$GLOBALS['defaults']['var_name']['display']" does contain the string THIS_IS_A_CONSTANT then all you should need to do is pass that string to the constant funct.
Am I missing something?