I am trying to make a site multi lingual. by building a language dictionary array ( if it is not the best way please don't hesitate to let me know )
$fr=array();
$fr['hello']="Bonjour";
I would like to make a function that does the following :
for every word and language function ( $word ="hello",$language="fr")
it would return the right value. So far the way I am doing isn't working
echo $$language[$word];
any ideas?
thank you
By default, variables are local to a function. If your dictionary arrays are global, you need to declare them as global, but since the names are variable, you have to access them via $GLOBALS:
function foo($word, $language) {
echo $GLOBALS[$language][$word];
}
As for a better way, you might want to use just one multi-dimensional array instead of creating one variable for each language:
$dict = array();
$dict['fr']['hello'] = 'Bonjour';
function foo($word, $language) {
global $dict;
echo $dict[$language][$word];
}
A few things to mention here...
I would recommend using actual "locales" (a language code plus country code) to reference your languages rather than your two letter country code. Your example includes "fr" for French. Typical convention is to use locale names instead. For example fr_FR for French (France) and fr_CA for French (Canadien). Language can very greatly based on country (if you're a native US English speaker and take a trip to Australia, you'll understand what I'm talking about).
Depending on the size of your site, you probably don't want to keep this as a PHP dictionary/assoc array. There are lots of options here (putting translations in a database, shared memory, etc.). If you do keep it in PHP memory, opcode caching would be a great idea and is relatively easy to setup. I would encourage you to look at how other frameworks achieve this (and ideally maybe use an existing framework to achieve this).
You mention translating "words". Generally, when internationalizing a site, you want to translate phrases. Translating words and then gluing them together typically results in poor translations.
If you do stick with the dict route, I would highly encourage you to drop the dynamic interpretation of the the variable name/language name in favor of a nested associative array. For example $dict['fr_FR']['hello'] = 'bonjour';
You might want to consider using a single (nested) array
$strings = array(
"french" => array(
"stringID" => "foobar"
)
);
echo( $strings["french"]["stringID"] );
If you are not utilising a database I would highly recommend looking into this. MySQL and PostgreSQL tend to be popular choices for independent and small development shops.
$$language[$word] didn't work
the work around was
$arr=$$language;
$arr[$word];
Related
This question already has answers here:
How to ConfigParse a file keeping multiple values for identical keys?
(5 answers)
Closed 9 years ago.
I have read this post, and defined an array in subscriber.ini
[smtp]
subscriber[] = aaa#hotmail.com
subscriber[] = bbb#XX.webmail
subscriber[] = ccc#test.org
Then I try to use ConfigParser to read the array
#!/usr/bin/python
import ConfigParser
CONFIG_FILE = 'subscriber.ini'
config = ConfigParser.ConfigParser()
config.read( CONFIG_FILE )
subscriber = config.get('smtp' , 'subscriber[]' )
print subscriber
It will output the last element, ccc#test.org. But I expect a full subscriber list.
How do I get the array from ini file ?
Python ConfigParser doesn't provide this feature. Use following instead:
[smtp]
subscriber = aaa#hotmail.com bbb#XX.webmail ccc#test.org
Then in your script:
subscriber = config.get('smtp' , 'subscriber').split()
This syntax, where subscriber[] automatically makes subscriber into a list of multiple values, is not a feature of .ini files in general, nor of ConfigParser; it's a feature of Zend_Config_Ini.
In Python, a ConfigParser ini file creates a dict mapping each key to its value. If you have more than one value, it will just override previous values. The magic [] suffix means nothing.
However, the ConfigParser constructor lets you specify a custom dictionary type or factory, in place of the default OrderedDict.
One simple solution would be to use a defaultdict(list) (or an OrderedDefaultDict, which there are recipes for in the docs) for the underlying storage, have __setitem__(self, key, value) do self.dd[key].append(value), and delegate everything else normally. (Or, if you prefer, inherit from defaultdict, override the constructor to pass list to the super, and then just don't override anything but __setitem__.) That will make all of your values into lists.
You could even do something hacky where a value that's only seen once is a single value, but if you see the same name again it becomes a list. I think that would be a terrible idea (do you really want to check the type of config.get('smtp', 'subscriber[]') to decide whether or not you want to iterate over it?), but if you want to, How to ConfigParse a file keeping multiple values for identical keys? shows how.
However, it's not at all hard to reproduce the exact magic you're looking for, where all keys ending in [] are lists (whether they appear once or multiple times), and everything else works like normal (keeps only the last value if it appears multiple times). Something like this:
class MultiDict(collections.OrderedDict):
def __setitem__(self, key, value):
if key.endswith('[]'):
super(MultiDict, self).setdefault(key, []).append(value)
else:
super(MultiDict, self).__setitem__(key, value)
This obviously won't provide all of the extended features that Zend_Config_Ini adds on top of normal .ini files. For example, [group : subgroup : subsub] won't have any special meaning as a group name, nor will key.subkey.subsub as a key name. PHP values TRUE, FALSE, yes, no, and NULL won't get converted to Python values True, False, True, False, and None. Numbers won't magically become numbers. (Actually, this isn't a feature of Zend_Config_Ini, but a misfeature of PHP's leaky typing.) You have to use # comments, rather than freely mixing #, ;, and //. And so on. Any of those features that you want to add, you'll have to add manually, just as you did this one.
As I suggested in a comment, if you really want to have more than two levels of hierarchy, you may be better off with a naturally infinitely-hierarchical format, where any value can be a list or dict of other values.
JSON is ubiquitous nowadays. It may not be quite as human-editable as INI, but I think more people are familiar with it than INI in 2014. And it has the huge advantage that it's a standardized format, and that both Python (2.6+) and PHP (5.2+) come with parsers and pretty-printers for in their standard libraries.
YAML is a more flexible and human-editable format. But you will need third-party modules in both languages (see the list at the YAML site). And it can also bring in some security concerns if you're not careful. (See safe_load and friends in the PyYAML docs; most other libraries have similar features.)
I wonder if you have considered using Michael Foord's configobj module? It seems to be capable
of doing what you want, which might be better that trying to pervert ConfigParser to do what you apparently need.
In the language of Perl, I define a hash as a mapping between one thing and another or an essential list of elements. As stated in the documentation..
A hash is a basic data type. It uses keys to access its contents.
So basically a hash is close to an array. Their initializations even look very similar.
If I were to create a mapping in Perl, I could do something like below for comparing.
my %map = (
A => [qw(a b c d)],
B => [qw(c d f a)],
C => [qw(b d a e)],
);
my #keys = keys %map;
my %matches;
for my $k ( 1 .. #keys ) {
$matches{$_} |= 2**$k for #{$map{ $keys[$k-1] }};
}
for ( sort keys %matches ) {
my #found;
for my $k ( 1 .. #keys ) {
push #found, $keys[$k-1] if $matches{$_} & 2**$k;
}
print "$_ found in ", (#found? join(',', #found) : 0 ), "\n";
}
Output:
a found in A,C,B
b found in A,C
c found in A,B
d found in A,C,B
e found in C
f found in B
I would like to find out the best method of doing this for performance and efficiency in php
If I understand correctly, you are looking to apply your knowledge of Perl hashes to PHP. If I'm correct, then...
In PHP a "Perl hash" is generally called an "associative array", and PHP implements this as an array that happens to have keys as indexes and its values are just like a regular array. Check out the PHP Array docs for lots of examples about how PHP lets you work with arrays of this (and other) types.
The nice thing about PHP is it is very flexible as to how you can deal with arrays. You can define an array as having key-value pairs then treat it like a regular array and ignore the keys, and that works just fine. You can mix and match...it doesn't complain much.
Philosophically, a hash or map is just a way to keep discrete pieces of related information together. That's all most non-primitive data structures are, and PHP is not very opinionated about how you go about things; it has lots of built-in optimizations, and does a pretty solid job of doing these types of things efficiently.
To answer your questions related to your example:
1) As for simplicity (I think you mean) and maintainability, I don't think there's anything wrong with your use of an associative array. If a data set is in pairs, then key-value pairs is a natural way to express this type of data.
2) As for most efficient, as far as lines of code and script execution overhead goes...well, the use of such a mapping is a vanishingly small task for PHP. I don't think any other way of handling it would matter much, PHP can handle it by the thousands without complaint. Now if you could avoid the use of a regular expression, on the other hand...
3) You're using it, really. Don't over think it - in PHP this is just an "array", and that's it. It's a variable that holds an arbitrary amount of elements, and PHP handles multiple-dimensions or associativity pretty darn well. Well enough that it's almost never going to be the cause of any problem you have.
PHP will handle things like hash/maps behind the scenes very logically and efficiently, to the point that part of the whole point of the language is for you not to bother to try to think about such things. If you have relates pieces of data in chunks, use an array; if the pieces of data comes in pairs, use key-value pairs; if it comes by the dozen, use an "array of arrays" (a multidimensional array where some - or all - of it's elements are arrays).
PHP doesn't do anything stupid like create a massive overhead just because you wanted to use key-value pairs, and it has lots of built-in features like foreach $yourArray as $key => $value and the functions you used like array_keys() and array_values(). Feel free to use them - as core features they are generally pretty darn well optimized!
For what you are doing I would rather use sprintf:
$format = 'Hello %s how are you. Hey %s, hi %s!';
printf($format, 'foo', 'bar', 'baz');
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
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", ... );
?>