I have a function L($key) that translates my strings.
Nothing fancy:
$_langs = include(__DIR__ . '/lang.php');
function L($key)
{
global $_langs;
if (array_key_exists($key, $_langs)) {
return $_langs[$key];
} else {
return $key;
}
}
When I need parametrized translation (with %s), I use this:
sprintf(L('myKey'), $var)
Is there some easy way to make it so I can use just L('myKey', $var)?
I thought of adding array $params=null as a formal parameter (It'd then take array as second argument), but how can I then expand it to individual arguments of sprintf()?
As usual, I've figured it out right after asking ^^
Here's my solution - if you can write it better, feel free to answer and I can accept it.
// i18n utility
$_langs = include(__DIR__ . '/lang.php');
function L($key)
{
global $_langs;
if (array_key_exists($key, $_langs)) {
$formats = array_slice(func_get_args(), 1);
$sprintf_args = array_merge([$_langs[$key]], $formats);
return call_user_func_array('sprintf', $sprintf_args);
} else {
return $key;
}
}
Related
So I have a single method that generated a cache key and also applies a transient automatically.
Here is the method:
private function get_cache($id, $count)
{
$cache_key = $this->generate_cache_key($id, $count);
return get_transient($cache_key);
}
How could I make that method return both the $cache_key but also get_transient?
Here is what I'm trying to achieve:
Access the $cache_key inside another method.
Also execute the get_transient when calling the method.
I have a method and this is what I'm aiming to achieve:
public function delete_cache($count = 4)
{
$cache_key = $this->get_cache['cache_key'];
var_dump($cache_key);
}
So I was thinking something like $instagram->get_cache['cache_key'] but also keep the original functionality for:
if ($cached = $instagram->get_cache($instagram->user_id, $count)) {
return $cached;
}
Does anyone know how I can get the cache_key for another method, but still keep the get_transient return?
The concept of returning multiple values from a function is called a "tuple". Almost every language implements this to some degree, sometimes as a "record", sometimes as a "database row", or maybe as a struct. For PHP, you are pretty much limited to either an object with fields, or an array, with the latter being the most common. Your get_cache function could be reworked as:
private function get_cache($id, $count)
{
$cache_key = $this->generate_cache_key($id, $count);
return [$cache_key, get_transient($cache_key)];
}
And to invoke it you'd do:
[$cache_key, $value] = $this->get_cache('a', 4);
Or, if using an older version of PHP (or you just don't like the look of that):
list($cache_key, $value) = $this->get_cache('a', 4);
The downside of this is that all callers have to be changed to support this, which may or may not be a problem. An alternative is to add an optional callback to the function that performs more work:
private function get_cache($id, $count, callable $func = null)
{
$cache_key = $this->generate_cache_key($id, $count);
$value = get_transient($cache_key);
if(is_callable($func)){
$func($cache_key, $value);
}
return $value;
}
And call it like:
$value = $this->get_cache(
'a',
4,
static function($cache_key, $value) {
var_dump($cache_key);
}
);
Although you are using WordPress, I think it is helpful to see what other frameworks do, too. PSR-6 defines something called CacheItemInterface which is the object-form of the return, and Symfony's cache (which you can actually use in WordPress, I do sometimes on large projects) uses the get-with-callback syntax.
You could return an array of those two values
private function get_cache($id, $count)
{
$cache_key = $this->generate_cache_key($id, $count);
return [$cache_key, get_transient($cache_key)];
}
// ...
[$cache_key, $transient] = get_cache($id, $count);
I am writing some PHP code that would generate HTML files from templates.
I would like, if possible, to make a function that would take any strings I feed the function with, and put that into the file. Like so:
function generator($a, $b, $c, $n...){
$filename = $a . ".html";
ob_start ();
echo $b;
echo $c;
echo $d;
echo $n...;
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
I need this, because different pages would have different number of include files, and with this I would be able to skip making different functions for specific pages. Just an iterator, and that's it.
Thanks!
From PHP 5.6+ you can use ... to indicate a variable number of arguments:
function test (... $args)
{
foreach ($args as $arg) {
echo $arg;
}
}
test("testing", "variable"); // testing variable
Demo
Variable-length argument lists from the manual
So, your function would look something like this:
function generator($a, $b, $c, ... $n) {
$filename = $a . ".html";
ob_start();
echo $b;
echo $c;
foreach ($n as $var) {
echo $var;
}
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
You can also use variadic functions (PHP 5.6+) :
function generator($a, ...$args) {
echo $a . "\n";
print_r($args);
}
generator("test", 1, 2, 3, 4);
Outputs :
"test"
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
You can make it using an array as following :
function generator($array){
// set the first item of the array as name of the .html file and take it out of the array.
$filename = array_shift($array) . ".html";
ob_start ();
// echo all the array fields
foreach($array as $a){
echo $a;
}
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
You can pass the array directly to call the function like the following :
generator( ["val_1", "val_2", "val_3"] );
Just use func_get_args(); inside your function to return an array of all arguments passed in.
You can also use func_get_arg($arg_num) to return a specific argument, or func_num_args to return the number of arguments.
All PHP functions allow any number of parameters, they just won't be callable by name, the only way is with these 3 functions.
Note, you may use a variadic argument as the last in the parameter list like so:
function my_func($x,$y, ... $z){
//Now $z is an array of all arguments after the first two
}
In the process of good design, I would think carefully about when and where to use things such as this. For example I currently work on a project that probably has over 200K lines of code and for better of worse this is actually never used.
The most common way is to pass an array "struct" to the method:
$args = array();
$args['kitchen'] = 'sink';
$args['bath'] = 'room';
$args['cat'] = array('fur','tail');
$func->someFunction($args);
If you wanted to have more control over the data you could create a struct and access that within the class. Public functions act as handlers.
class SomeClass {
....
private $args
public function setArgs($arg1,$arg2,$arg3) {
$this->arg1 = $arg1;
...
}
public function getArgs() {
return $this->args;
}
More rarely you can have C++ like control where you use a class just as a struct:
class MyStruct {
public $foo;
public $bar;
private $secret;
private function getSecret() {
return $secret;
}
protect function setSecret($val) {
$secret = $val;
}
}
Already mentioned is '...' which I nearly never see but it's interesting, though how useful ? Does this help explain what is going on?
function someFunction(... $args)
Usually you will see a mix of things in methods which helps articulate the purpose of it.
private function someSmallFunc($list = array(), $val = '', $limit = 10)
This example is to illustrate the natural grouping of information, data is in a list, $val is used for something to control the method along with $limit say limits the number of query results. Hence, you should think in this way about your methods IMO.
Also if you notice default values are set ($limit = 10) to in case they aren't passed in. For example if you call someSmallFunc($data, $someVal) (opposed to say someSmallFunc($data, $someVal, 20) ) and not pass in $limit it will default to 10.
If certain elements are contained in an array, I want them moved to the start of it.
At first I used a bunch of array_diff_keys to get it to work, but I wanted something more elegant. So I tried using uksort with a callback, but perhaps I'm doing it wrong because it's not working.
I tried this, it's a method of my helper class, but it's not working.
$good_elements = array('sku','name','type','category','larping');
$test_array = array('sku','name','asdf','bad_stuff','larping','kwoto');
$results = helper::arrayPromoteElementsIfExist($test_array,$good_elements,false);
public static function arrayPromoteElementsIfExist($test_array,$promote_elements,$use_keys = false) {
foreach(array('test_array','promote_elements') as $arg) {
if(!is_array($$arg)) {
debug::add('errors',__FILE__,__LINE__,__METHOD__,'Must be array names',$$arg);
return false;
}
}
if(!$use_keys) {
$test_array = array_flip($test_array); // compare keys
$promote_elements = array_flip($promote_elements); // compare keys
}
uksort($test_array,function($a,$b) use($promote_elements) {
$value1 = intval(in_array($a, $promote_elements));
$value2 = intval(in_array($b,$promote_elements));
return $value1 - $value2;
});
if(!$use_keys) {
$test_array = array_flip($test_array);
}
return $test_array;
}
Fairly quick and dirty but here you go.
function promoteMembers($input, $membersToPromote)
{
$diff = array_diff($input, $membersToPromote);
return array_merge($membersToPromote, $diff);
}
Assuming I understood what you wanted to do.
Example output: for your verification.
Is there a trick in PHP 4 to implement functions which return functions? I expected that the following code would work:
function xxx($a) {
return function($b) {
print "a=$a, b=$b \n";
}
}
$f1 = xxx(1);
$f1(2);
Unfortunately, no luck in PHP 4. Probably it works in PHP 5, but I limited to PHP 4.
I tried to workaround with OO, but again failed (class declarations may not be nested):
class Closure {
function run($a) {
print "raise: NotImplementedException, instead: $a\n";
}
}
class WantCheckNesting extends Closure {
function run($a, $b) {
class Nested extends Closure {
function run($c) {
print "a=$a, b=$b, c=$c\n";
}
}
$o = new Nested();
return $o;
}
}
$d = new WantCheckNesting();
$e = $d->run(2, 3);
$e->run(4);
There is a function "create_function", but it is very limited: the body must be a string.
Any other ideas?
You're probably barking at the wrong tree. PHP is not a functional programming language. Some changes have been made starting with PHP 5.3, but even there you don't have your expected variable scopes that would allow you to do what you have in your examples.
The only tools you can use in PHP 4 are create_function and some ingenuity to write the function definition as a string.
<?php
function getMyFunc($a){
return create_function('$b', 'print "a='.$a.', b=$b";');
}
$f1 = getMyFunc(1);
$f1(2);
?>
...but even if this is simple for your posted example, it definitely isn't practical for more complex situations.
In PHP4 you can use Variable Functions like this, provided your function is already defined in the scope (so not a real closure).
THIS IS DIRTY CODE.
THIS IS NOT MUCH TESTED.
THIS IS NOT FAST (even slower than closures if that is possible).
It is just for fun and proving it "somehow" can be done if you really really need it.
Requires a writable tmp/ directory.
<?php
function xxx($a) {
$sid = GetUniversalSessionId();
$tmpfname= 'tmp/'.$sid.'.php';
$handle = fopen($tmpfname, "w");
fwrite($handle, '<?php
function func_'.($sid).'($b) {
$a='."'".str_replace("\'","\\'",str_replace("\\","\\\\",$a))."'".';
print "a=$a, b=$b \n";
}
?>');
fclose($handle);
include($tmpfname);
unlink($tmpfname);
return 'func_'.($sid);
}
$result=xxx(32);
$result(20);
// This is just to get a unique identifier for every connection and every function call:
// UNIVERSALSESSIONIDS v1.3
if(defined('UNIVERSALSESSIONIDS')) return;
define('UNIVERSALSESSIONIDS', TRUE);
function GetTimeStart() {
return strtotime('2006-07-10');
}
function GetUniversalSessionId() {
return GetCodedSid(letterNumBase(),16);
}
function GetCodedSid($baseChars,$Pad=0) {
$Zero=$baseChars{0};
list ($usec, $sec) = explode (' ', microtime());
$new_sid = ($sec-GetTimeStart()) . str_pad ((int)($usec * 100000000), 8, '0', STR_PAD_LEFT) . str_pad (rand (0, 9999), 4, '0', STR_PAD_LEFT);
$new_sid=ConvertDecToAnyStr($new_sid,$baseChars);
$new_sid=str_pad ($new_sid, $Pad, $Zero, STR_PAD_LEFT);
return $new_sid;
}
function divide($decstr,$decnum) {
$Start='';
$Result='';
$WRITE=FALSE;
do {
$Start.=substr($decstr,0,1);
$decstr=substr($decstr,1);
$DecStart=intval($Start);
$Rest=$DecStart%$decnum;
$PartDiv=($DecStart-$Rest)/$decnum;
if($PartDiv>0) $WRITE=TRUE;
if($WRITE) $Result.=$PartDiv;
$Start=$Rest;
} while ($decstr!='');
if($Result=='') $Result='0';
return array($Result,$Rest);
}
function bigBase() {
global $gSavedBigBase;
if(isset($gSavedBigBase)) return $gSavedBigBase;
$BigBase='';
for($i=33;$i<=128;$i++) $BigBase.=chr($i);
$gSavedBigBase=$BigBase;
return $BigBase;
}
function letterNumBase() {
global $gSavedBigBase2;
if(isset($gSavedBigBase2)) return $gSavedBigBase2;
$BigBase='';
for($i=ord('0');$i<=ord('1');$i++) $BigBase.=chr($i);
for($i=ord('A');$i<=ord('Z');$i++) $BigBase.=chr($i);
$BigBase.='_';
// for($i=ord('a');$i<=ord('z');$i++) $BigBase.=chr($i);
$gSavedBigBase2=$BigBase;
return $BigBase;
}
function ConvertDecToAny($decstr,$decbase) {
$Result=array();
do {
$Div=divide($decstr,$decbase);
$decstr=$Div[0];
$Rest=$Div[1];
$Result[]=$Rest;
} while($decstr!='0');
return $Result;
}
function ConvertDecToAnyStr($decstr,$baseChars='01') {
$decbase=strlen($baseChars);
$Result='';
do {
$Div=divide($decstr,$decbase);
$decstr=$Div[0];
$Rest=$Div[1];
$Result=$baseChars{$Rest}.$Result;
} while($decstr!='0');
return $Result;
}
?>
I'm using PHP's global declaration to make an array available to a number of functions in a script. The variable is declared at the top of the script and is referenced with global in each of the functions which uses it, as follows:
<?php
$myarray = array(1, 2, 3);
function print_my_array() {
global $myarray;
print '<ul>';
foreach($myarray as $entry) {
print '<li>'.$entry.'</li>';
}
print '</ul>';
return 0;
}
print_my_array();
?>
Sometimes, but not always, the array is not set when the function is called, generating an error when the foreach is called. In the actual code, the array used is given a very unique name and so should not be causing any collisions with anything else. Am I mis-using the global declaration?
No, the snippet is correct. The problem you're having is the problem of using global variables – they can be accessed and changed from anywhere (perhaps accidental), thereby creating hard-to-find bugs.
By using globals you can hit quite a few gotchas, they'll also make you code less reusable.
Here's an example of your function which can be re-used many times across the site.
(untested)
<?php
function arrayTags($items, $open = '<li>', $close = '</li>')
{
if (is_array($items) && count($items) != 0)
{
$output = null;
foreach ($items as $item) {
$output .= $open . $item . $close;
}
return $output;
}
else
{
return '';
}
}
// Default, <li>
echo '<ul>' . arrayTags($myarray) . '</ul>';
// or, spans:
echo '<div id="container">' . arrayTags($myarray, '<span>', '</span>') . '</div>';
The least you could do is check if the array is null at the top of the function, before you run the foreach. that would at least prevent the error:
function print_my_array() {
global $myarray;
if(!empty($myarray)) {
print '<ul>';
foreach($myarray as $entry) {
print '<li>'.$entry.'</li>';
}
print '</ul>';
}
}
Also, I wouldn't just return 0 for the hell of it. You may want to incorporate whether or not the array was empty into what you return from this function.
$myarray = array(1, 2, 3);
In short you have to only declare it like so:
$myarray = array();
and if you want to populate it with values do that in the class constructor:
public function __construct(){
$myarray = array(1,2,3);
}
I'm no guru, but in my experience it seems that php doesn't like to execute function calls outside of a function within a class.
THIS DOES NOT WORK:
class MyClass {
public $mystring = myfunction();
public function myFunction(){
return true; //and your function code
}
}
so when you use array() it doesn't actually trigger any function call, it just creats an empty variable of type array. when you use array(1,2,3), it has to effectively run the 'create array' which is like a function.
I know annoying, I'd like it to be different, but I don't know a way of doing what you want in php. Let me know if there is a nice way I'd love to hear it!