mass pass-by-reference for string changing functions? - php

For string functions, I find myself doing this kind of thing a lot:
$string = trim($string);
I would like to easily have functions where I can pass the string by reference, so I can instead do function($string);.
I was thinking about writing wrappers for all the string functions I want to use, and prefix it with a special character, like so:
function _trim(&$string) {
trim($string);
}
function _str_replace($a, $b, &$string) {
str_replace($a, $b, $string);
}
But I wonder if there's a way that's easier than writing a wrapper for each function? (Has someone written this library already?)

For functions that can take only one argument (the string) like trim(), strtolower() etc, you could do something like this maybe...?
function modify_str (&$str, $funcName) {
if (function_exists($funcName)) $str = $funcName($str);
}
// So you can now do
modify_str($str, 'trim');
modify_str($str, 'strtolower');
...but to be perfectly honest, I cant really see the point - for one thing, you can't chain functions that take an argument by reference (i.e. you can't do trim(strtolower($str)))
I tend not to write $str = trim($str); very much, because I am probably going to use the result fairly immediately in some other operation. Instead of this:
$str = trim($str);
some_func($str, $someOtherVar);
I just do this:
some_func(trim($str), $someOtherVar);
And in the event that I need to do something like this:
$str = trim($str);
some_func($str, $someOtherVar);
another_func($str, $yetAnotherVar);
I would do this:
some_func($str = trim($str), $someOtherVar);
another_func($str, $yetAnotherVar);
...but whatever you are trying to do by doing any of the above, what you are effectively achieving is making your code less readable, and probably nothing else.
EDIT
After doing something completely unrelated today, I realised there is a way to chain functions and call it by reference:
function modify_str (&$str) {
$args = func_get_args();
for ($i = 1; isset($args[$i]); $i++) {
if (function_exists($funcName = $args[$i])) $str = $funcName($str);
}
}
// So you could do
modify_str($str,'trim','strtolower');
...but I still maintain this is not the way to go.
ANOTHER EDIT
You could pass to functions that uses multiple arguments by doing something like this (untested):
function modify_str (&$str) {
$str_identifier = '$$$'; // This identifies the argument where $str should be used
$ops = func_get_args();
for ($i = 1; isset($args[$i]); $i++) { // Loop functions to be applied
if (function_exists($ops[$i]['function'])) {
$args = array();
for ($j = 0; isset($ops[$i][$j]); $j++) { // Loop arguments for this function and build an argument list in PHP syntax
$args[] = ($ops[$i][$j] === $str_identifier) ? '$str' : "\$ops[\$i][$j]";
}
// eval() it (as if you had written it as straight PHP)
eval("\$str = {$ops[$i]['function']}(".implode(',',$args).");");
}
}
}
// So you can call it like this
modify_str($str,array('function'=>'str_replace','&','&','$$$'),array('function'=>'explode',"\n",'$$$'));
// ..which should have the same effect as
$str = explode("\n",str_replace('&','&',$str));
// As you can see, the not-by-reference way is is much shorter and more readable

Related

Can a PHP define be used for a function with an argument

I am writing a script that generates HTML based on what is currently in a database and I prefer to have the HTML be formatted, particularly with tabs to show nesting. I have a simple function to generate some number of tabs:
function addTab($inNum) {
$out = "";
for ($i = 0; $i < $inNum; $i++) $out .= "\t";
return $out;
}
For convenience of reading the PHP, I made this:
$T = "addTab";
So that I could just use $T(5) to say concatenate 5 \t to the string HTML. Personally I find this kind of syntax of pointing to a function by string to be unintuitive and functions that use it require global $T.
Is it possible to use a define() so that something like T(5) could be used within function scope?
No, you cannot "define a function" in the way you desire.
Why not use:
function T($inNum)
{
return addTab($inNum);
}
Then you can just write T(5), as you mentioned.
When you use define you define a constant.
According to manual:
The value of the constant; only scalar and null values are allowed. Scalar values are integer, float, string or boolean values. It is possible to define resource constants, however it is not recommended and may cause unpredictable behavior.
So you can't define a constant with the value of a function.
But still function variables are working in php:
function addTab($inNum) {
$out = "";
for ($i = 0; $i < $inNum; $i++) $out .= "*";
return $out;
}
$T = 'addTab';
$r = $T(5);
var_dump($r); // string(5) "*****"

How to know the match count in preg_replace_callback - PHP

I have this code in php -:
function pregRepler($matches)
{
* do something
}
$str = preg_replace_callback($reg_exp,'pregRepler',$str);
When in function pregRepler, i would want to know the current match number like if it is the first match or the second or anything...
How do i do it.??
Try something like this:
function pregRepler($matches) {
static $matchcount = 0;
// do stuff
$matchcount++;
}
This works better with an anonymous function, as I mentioned in my answer to your other question, as this will avoid problems if you have multiple calls to preg_replace_callback.
You need to share a $count variable between both variable scopes, for example by using a variable alias:
$callback = function($matches) use (&$count) {
$count++;
return sprintf("<%d:%s>", $count, $matches[0]);
};
echo preg_replace_callback($pattern, $callback , $subject, $limit = -1, $count);
Before invoking, $count is equal to 0. After invoking $count is set to the number of replacements done. In between you can count up in your callback. You can also set to zero again when calling another time.
See it in action
See http://php.net/preg_replace_callback
$repled = 0;
function pregRepler($matches)
{
* do something
global $repled;
$repled++;
}
$str = preg_replace_callback($reg_exp,'pregRepler',$str);
Just count from a global variable.

possible limitation of implode function in PHP

I have the following code that is not returning as I expected. I was hoping the final result would be a string:
$organizers = array_unique($organizers); // this returns correctly
$organizers = implode(', ', $organizers); // this returns nothing
var_dump($organizers); // no data appears here
exit;
The array_unique() function is returning data correctly and I can see the array it returns. To start, the $organizers array is a simple 1-D array of strings that all have small lengths under 20 chars. I think the issue might be that $organizers is more than 10,000 indices long. Are there limitations on the length of an array that can be imploded? Are there work-arounds for that? I cannot find anything in the manual, but I have tested this code thoroughly and I believe the error must be on implode().
I dont' know if there is a limitation, but what comes to my mind is taht you are also transforming an array into a string. This shouldn't be the problem in PHP, but try calling it a different variable for the result of implode?
$organizers = array_unique($organizers); // this returns correctly
$organizers_string = implode(', ', $organizers); // this returns nothing
// This gives it a different space
Edit: And if for some reason implode() is still problematic.
$organizers = array_unique($organizers);
$neworganizers = "";
for($i = 0; $i < sizeof($organizers); $i++)
{
$neworganizers .= $organizers[$i];
if($i != sizeof($organizers) - 1)
{
$neworganizers .= ", ";
}
}
//$neworganizers is now the equivalent of what .implode() should return when called on $organizers
$organizers = array();
$organizers[0] = "value1";
$organizers[1] = "value2";
$organizers[2] = "value3";
$organizers[3] = "value3";
$organizers = array_unique($organizers); // strips out last index
$organizers = implode(', ', $organizers); // returns string of "value1, value2, value3"
echo $organizers;
This seemed to work on writecodeline.com/php/
I've also experienced issues with older php builds when I've tried to explode/implode by a string with special characters in it and they were encapsulated by single quotes. I know it sounds crazy, but the double quotes might be necessary on some servers.
Reference: personal experience doing work on older production servers.
I'd hate to think I'm stating the obvious, but doesn't implode only take a string as an argument? Maybe it should be something more like this...
$organizers = array_unique($organizers);
//I'm guessing what you wanted was an array of arrays?
$neworganizers = array();
for($i = 0; $i < sizeof($organizers); $i++)
{
$neworganizers[$i] = implode(", ", $organizers);
}
print_r($neworganizers);

No Output? PHP foreach doesn't seem to work

I am trying to form an acronym from a given text. The Idea here is that the first Letter in $text ($text[0]) will be taken and placed inside the array $storage using array_push(). Now, if there is a space inside the array, the letter of the next index should be a part of the Acronym. I am currently not getting an ouput, what am I missing?
public function Acronym($text)
{
$text = str_split($text);
$count = strlen($text);
$storage = array();
for($i=0; $i<$count; $i++)
{
array_push($storage, $text[0]);
if($text[$i]==' ')
{
array_push($storage, $text[$i+1]);
}
foreach($storage as $clean)
{
echo $clean;
}
}
}
Your algorithm suffers from a few fatal flaws:
You're calling strlen() on an array, when you should be calling count():
$text = str_split($text);
$count = count($text);
However, you can index strings as arrays, so you don't need str_split() in this scenario, and you can keep $count = strlen( $text); by removing the call to str_split().
This should only happen once, so it should be outside the loop (This implies starting $i at 1):
array_push($storage, $text[0]);
Your foreach loop that prints the $storage array should be outside of the loop that is creating the acronym.
You can save the overhead of calling a function by using the shorthand array_push() notation. You should use array_push() when adding more than one element to an array. Otherwise, this will suffice:
$storage[] = $text[0];
You need to return something from your function, otherwise you won't be able to access anything outside of it.
Put that all together, and you get this:
public function Acronym($text)
{
$count = strlen( $text);
$storage[] = $text[0];
for( $i = 1; $i < $count; $i++)
{
if( $text[$i] == ' ')
{
$storage[] = $text[$i+1]);
$i++; // Can increment $i here because we know the next character isn't a space
}
}
foreach($storage as $clean)
{
echo $clean;
}
return $storage;
}
That being said, there are far better implementations for forming an acronym giving a string input. Here is one that I can think of:
public function Acronym( $text)
{
$acronym = array();
foreach( explode( ' ', $text) as $word)
{
$word = trim( $word);
$acronym[] = strtoupper( $word[0]);
}
return implode( '', $acronym);
}
Note that both functions will fail for inputs like Hello World. I am leaving it up to the OP to make these modifications (if necessary).
str_split turns the string into an array.
str_length brings the length of a string which you have overwritten with an array already. you need count()
You overwrite your first variable $text
$count = strlen($text);
In this line $text is an array, because you changed it in the first line of your method.
Try inverting the two first lines:
$count = strlen($text);
$text = str_split($text);
Note
This will solve your secondary problem, and enable your algorithm to run without errors. It doesn't fix your algorithm, but at least you will be able to debug it now.
you are running your loop on $count which is getting its value from str_len its an array because of return on $text = str_split($text);
So you have overwritten your $text variable you can fix it by changing order get length first then split.

Generate comma seperated string list from array PHP

I am trying to write a function in PHP, but being a novice I am finding it a bit difficult to do so. I have an array which looks like
[{"x":"12345","y":"john"},{"x":"12345","y":"stars"}]
The function which I am writing is
function getCSV($x)
{
// Now I want to pass the $x which in the above array is 12345 and get "john,stars" as output
}
Are there any methods available in PHP that can do this, or what would be the best approach to get it?
That looks like a json to me
[{"x":"12345","y":"john"},{"uid1":"12345","uid2":"stars"}]
function getCSV($x)
{
$arr = json_decode($x);
echo $arr[0]->y . ', ' . $arr[1]->uid2;
}
This looks horrible, but withouth further explanation is the only thing that works
EDIT - after your edit
function getCSV($x)
{
$arr = json_decode($x);
$y = array();
foreach($arr as $obj){
$y[] = $obj->y;
}
return implode(',', $y);
}
here is a working pad http://codepad.org/HzttdmjW

Categories