PHP function varying parameters - php

I couldn't find about my issue on google and SO. Hope, i can explain you.
You'll understand when looked following function:
function get_page($identity)
{
if($identity is id)
$page = $this->get_page_from_model_by_id($identity);
elseif($identity is alias)
$page = $this->get_page_from_model_by_alias($identity);
}
My used function:
get_page(5); // with id
or
get_page('about-us'); // with alias
or
get_page(5, 'about-us'); // with both
I want to send parameter to function id or alias. It should be only one identifier.
I dont want like function get_page($id, $alias)
How can i get and know parameter type with only one variable. Is there any function or it possible?

if(is_numeric($identity)) {
$page = $this->get_page_from_model_by_id($identity);
}
elseif(is_string($identity)) {
$page = $this->get_page_from_model_by_alias($identity);
}
elseif(func_num_args() === 2) {
$id = func_get_arg(0);
$alias = func_get_arg(1);
//do stuff
}

Use is_string() to find whether input is integer or character.

You should make use of func_get_args()
<?php
function foo()
{
$numargs = func_num_args();
echo "Number of arguments: $numargs<br />\n";
if ($numargs >= 2) {
echo "Second argument is: " . func_get_arg(1) . "<br />\n";
}
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++) {
echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
}
}
foo(1, 2, 3);
?>
Source

Here's a complete solution:
function get_page()
{
$alias = false;
$id = false;
foreach(func_get_args() as $arg)
if(is_string($arg))
$alias = $arg;
else if(is_int($arg))
$id = $arg;
}

Assuming id is always a number, you could test for it with php's is_numeric()
function get_page($identity)
{
if(is_numeric($identity) {
$page = $this->get_page_from_model_by_id($identity);
} else {
$page = $this->get_page_from_model_by_alias($identity);
}
}

Related

Multiple controllers?

I am using a MVC Framework for my PHP projects and how it works is as follows:
We have the a root that's like http://localhost/myproject.
And it accepts an url like this: http://localhost/myproject/example-controller/example-function/params
So what it does is it goes to the example-controller and executes the function example-function where we have the possibility to add parameters like http://localhost/myproject/example-controller/example-function/1/2/3
So I have a dashboard where I want to be able to apply crud functionality to users and articles so the url becomes as follows:
http://localhost/myproject/dashboard/users, which means that it will execute the function users but let's say I want to create a new user the link then becomes dashboard/users/create but it will see create as a parameter and not as an actual function that needs to be executed.. so I understand I would have to make a UserController and a ArticleController but that means the link will become user/create or article/create in which case it doesn't use the DashboardController anymore.
If anyone understood what I tried to describe could someone come up with a possible explanation on how to solve this issue.
I have found a solution to my problem and rewrote the whole splitUrl() function so it now accepts what I need.
function splitUrl()
{
if (isset($_GET['url'])) {
require(ROOT. 'core/routes.php');
$tmp_url = trim($_GET['url'], "/");
$tmp_url = filter_var($tmp_url, FILTER_SANITIZE_URL);
$tmp_url = explode("/", $tmp_url);
$param = ['params' => [], 'found' => false];
foreach ($routes as $route => $value) {
//echo("We iterate over a new route called <strong>". $route. "</strong><br>");
$tmp_route = explode("/", $route);
// Variables for the length of the arrays;
$route_count = count($tmp_route);
$url_count = count($tmp_url);
//echo("The route count = <strong>". $route_count . "</strong> and the url count = <strong>". $url_count. "</strong><br>");
// Check if the length of the route in our acceptable routes array is equal to the length of the url.
if ($route_count == $url_count) {
$indexCount = null;
for ($i = 0; $i < $route_count; $i++) {
if ($tmp_route[$i] == '{param}') {
$indexCount = $i;
//echo("A parameter has been found at index <strong>" . $indexCount . "</strong><br>");
break;
}
}
if ($indexCount == null) {
$indexCount = count($tmp_route);
//echo("A parameter has NOT been found so the index has been set to <strong>". $indexCount. "</strong><br>");
}
$doContinue = false;
for ($i = 0; $i < $indexCount; $i++) {
//echo("We are comparing value <strong>". $tmp_route[$i] . "</strong> to <strong>". $tmp_url[$i] ."</strong><br>");
if ($tmp_route[$i] == $tmp_url[$i]) {
//echo("Value <strong>". $tmp_route[$i] ."</strong> appears to be valid<br>");
continue;
} else {
//echo("Value <strong>". $tmp_route[$i] ."</strong> appears to be invalid<br><hr>");
$doContinue = true;
break;
}
}
if ($doContinue) continue;
$count = 0;
for ($i = 0; $i < $route_count; $i++) {
if ($tmp_route[$i] == $tmp_url[$count]) {
$count++;
continue;
} else {
array_push($param['params'], $tmp_url[$count]);
$count++;
}
}
} else {
// This means the route that we are iterating over right now can not possibly be the one we are looking for as the length is not equal to the length of the url.
continue;
}
$param['controller'] = explode("#", $value)[0];
$param['action'] = explode("#", $value)[1];
return $param;
}
}

Getting custom replace to work similar to how PHP PDO works

I just want to know how to replace a certain index character with an array constantly like how PDO works in PHP? Here is my code;
The the code
private $string;
public function __construct($string = null) {
if ($string !== null) {
$this->string = $string;
} else {
$this->string = '';
}
}
public function getString() {
return $this->string;
}
public function replaceWith($index, $array = array()) {
$lastArrayPoint = 0;
$i = 0;
while ($i < sizeof($this->string)) {
if (substr($this->string, $i, $i + 1) == $index) {
$newString[$i] = $array[$lastArrayPoint];
$i = $i . sizeof($array[$lastArrayPoint]);
$lastArrayPoint++;
} else {
$newString[$i] = $this->string[$i];
}
$i++;
}
return $this;
}
and the executing code
$string = new CustomString("if ? == true then do ?");
$string->replaceWith('?', array("mango", "print MANGO"));
echo '<li><pre>' . $string->getString() . '</pre></li>';
Thank you for the help I hope I will recieve.
$string = "if %s == true then do %s. Escaping %% is out of the box.";
$string = vsprintf($string, array("mango", "print MANGO"));
echo "<li><pre>$string</pre></li>";
str_replace has an optional count parameter, so you can make it replace one occurrance at a time. You can just loop through the array, and replace the next question mark for element N.
$string = "if %s == true then do %s";
$params = array("mango", "print MANGO");
foreach ($params as $param)
$string = str_replace('?', $param, $string, 1);
Thanks for the help guys but they did not work the way I wanted it to work. I have found a way to get it too work. Here is the code
public function replaceWith($index, $array = array()) {
$arrayPoint = 0;
$i = 0;
$newString = "";
while ($i < strlen($this->string)) {
if (substr($this->string, $i, 1) === $index) {
$newString .= $array[$arrayPoint];
$arrayPoint++;
} else {
$newString .= substr($this->string, $i, 1);
}
$i++;
}
$this->string = $newString;
return $this;
}
if anyone has a better way then you can tell me but for now this works.

Multiple optional argument in a function

getAllForms($data=null)
getAllForms() and getAllForms("data")
This will work. But I want to make two optional argument in a function like this:
getAllForms($arg1=null,$arg2=null)
getAllForms() and getAllForms("data")
How can I make this possible?
You can try:
function getAllForms() {
extract(func_get_args(), EXTR_PREFIX_ALL, "data");
}
getAllForms();
getAllForms("a"); // $data_0 = a
getAllForms("a", "b"); // $data_0 = a $data_1 = b
getAllForms(null, null, "c"); // $data_0 = null $data_1 = null, $data_2 = c
You can also try using func_get_arg which you can pass n number of arguments to a function.
http://php.net/manual/en/function.func-get-args.php
Example
function foo(){
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++) {
echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
}
}
foo(1, 2, 3);
Try this:
getAllForms($data=null,$data2=null)
and you call it in this mode:
getAllForms()
getAllForms("data")
getAllForms("data","data2")
The second argument have to be different name respect the first
You already described how you would do it:
function getAllForms($arg1 = null, $arg2 = null)
Except the every variable name (including the second) has to be different.
<? php
function getAllForms($data1 = null, $data2 = null)
{
if ($data1 != null)
{
// do something with $data1
}
if ($data2 != null)
{
// do something with $data2
}
}
?>
getAllForms();
getAllForms("a");
getAllForms(null, "b");
getAllForms("a", "b");
or
<? php
function getAllForms($data = null)
{
if (is_array($data))
{
foreach($data as $item)
{
getAllForms($item);
}
}
else
{
if ($data != null)
{
// do something with data.
}
}
}
getAllForms();
getAllForms("a");
getAllForms(array("a"));
getAllForms(array("a", "b"));
?>

set maximum of items that you can make in function

How can I say in/with the follow (see below) function that you can make max 3 items? And if you will make more than three items the function will stop and you get a warning?
function addSection() {
global $compid;
$sectionOb = new Item();
$sectionOb->i_id_pk = $sectionOb->newId();
$sectionOb->i_mod_comp_id_fk = $compid;
$sectionOb->c_titel = '';
$sectionOb->c_content = '';
$sectionOb->i_sort = $sectionOb->newSort($compid);
$sectionOb->insert();
}
if($action == 'add') {
addSection();
}
<a href="<?php echo $_SERVER['REQUEST_URI'] ?>&action=add" />new section</a>
Use a static counter variable:
function limited() {
static $invocationcount = 0;
++$invocationcount;
if($invocationcount <= 3) {
echo "You have called this function $invocationcount times.";
}
else {
echo "Stop doing that!";
}
}
See it in action.
If you are not too concerned about URL spoofing, I would add a counter variable in the URL which is passed to the addSection() method like so:
function addSection($count) {
if ($count >= 3) { return $count; }
global $compid;
$sectionOb = new Item();
$sectionOb->i_id_pk = $sectionOb->newId();
$sectionOb->i_mod_comp_id_fk = $compid;
$sectionOb->c_titel = '';
$sectionOb->c_content = '';
$sectionOb->i_sort = $sectionOb->newSort($compid);
$sectionOb->insert();
// Return incremented count
return $count + 1;
}
// Retrieve the last count from the URL
$count = isset($_GET['count']) ? intval($_GET['count']) : 0;
// Increment the count if the action is add and the addSection method suceedes
if($action == 'add') {
$count = addSection($count);
}
// Add count to the URL so we know what it is
<a href="<?php echo $_SERVER['REQUEST_URI'] ?>&action=add&count=<?php echo $count; ?>" />new section</a>
Thanks a lot for help!! I have do it as follow:
function limit() {
global $compid;
$i = 0;
++$i;
$a_all = page1::page2Id($compid);
$i = sizeof($a_all);
if($i <= 2) {
$sectionOb = section();
$sectionOb->i_id_pk = $sectionOb->newId();
$sectionOb->i_mod_comp_id_fk = $compid;
$sectionOb->c_titel = '';
$sectionOb->c_content = '';
$sectionOb->i_sort = $sectionOb->newSort($compid);
$sectionOb->insert();
return true;
}
else {
return false;
}
}

PHP recursive variable replacement

I'm writing code to recursively replace predefined variables from inside a given string. The variables are prefixed with the character '%'. Input strings that start with '^' are to be evaluated.
For instance, assuming an array of variables such as:
$vars['a'] = 'This is a string';
$vars['b'] = '123';
$vars['d'] = '%c'; // Note that $vars['c'] has not been defined
$vars['e'] = '^5 + %d';
$vars['f'] = '^11 + %e + %b*2';
$vars['g'] = '^date(\'l\')';
$vars['h'] = 'Today is %g.';
$vars['input_digits'] = '*****';
$vars['code'] = '%input_digits';
The following code would result in:
a) $str = '^1 + %c';
$rc = _expand_variables($str, $vars);
// Result: $rc == 1
b) $str = '^%a != NULL';
$rc = _expand_variables($str, $vars);
// Result: $rc == 1
c) $str = '^3+%f + 3';
$rc = _expand_variables($str, $vars);
// Result: $rc == 262
d) $str = '%h';
$rc = _expand_variables($str, $vars);
// Result: $rc == 'Today is Monday'
e) $str = 'Your code is: %code';
$rc = _expand_variables($str, $vars);
// Result: $rc == 'Your code is: *****'
Any suggestions on how to do that? I've spent many days trying to do this, but only achieved partial success. Unfortunately, my last attempt managed to generate a 'segmentation fault'!!
Help would be much appreciated!
Note that there is no check against circular inclusion, which would simply lead to an infinite loop. (Example: $vars['s'] = '%s'; ..) So make sure your data is free of such constructs.
The commented code
// if(!is_numeric($expanded) || (substr($expanded.'',0,1)==='0'
// && strpos($expanded.'', '.')===false)) {
..
// }
can be used or skipped. If it is skipped, any replacement is quoted, if the string $str will be evaluated later on! But since PHP automatically converts strings to numbers (or should I say it tries to do so??) skipping the code should not lead to any problems.
Note that boolean values are not supported! (Also there is no automatic conversion done by PHP, that converts strings like 'true' or 'false' to the appropriate boolean values!)
<?
$vars['a'] = 'This is a string';
$vars['b'] = '123';
$vars['d'] = '%c';
$vars['e'] = '^5 + %d';
$vars['f'] = '^11 + %e + %b*2';
$vars['g'] = '^date(\'l\')';
$vars['h'] = 'Today is %g.';
$vars['i'] = 'Zip: %j';
$vars['j'] = '01234';
$vars['input_digits'] = '*****';
$vars['code'] = '%input_digits';
function expand($str, $vars) {
$regex = '/\%(\w+)/';
$eval = substr($str, 0, 1) == '^';
$res = preg_replace_callback($regex, function($matches) use ($eval, $vars) {
if(isset($vars[$matches[1]])) {
$expanded = expand($vars[$matches[1]], $vars);
if($eval) {
// Special handling since $str is going to be evaluated ..
// if(!is_numeric($expanded) || (substr($expanded.'',0,1)==='0'
// && strpos($expanded.'', '.')===false)) {
$expanded = "'$expanded'";
// }
}
return $expanded;
} else {
// Variable does not exist in $vars array
if($eval) {
return 'null';
}
return $matches[0];
}
}, $str);
if($eval) {
ob_start();
$expr = substr($res, 1);
if(eval('$res = ' . $expr . ';')===false) {
ob_end_clean();
die('Not a correct PHP-Expression: '.$expr);
}
ob_end_clean();
}
return $res;
}
echo expand('^1 + %c',$vars);
echo '<br/>';
echo expand('^%a != NULL',$vars);
echo '<br/>';
echo expand('^3+%f + 3',$vars);
echo '<br/>';
echo expand('%h',$vars);
echo '<br/>';
echo expand('Your code is: %code',$vars);
echo '<br/>';
echo expand('Some Info: %i',$vars);
?>
The above code assumes PHP 5.3 since it uses a closure.
Output:
1
1
268
Today is Tuesday.
Your code is: *****
Some Info: Zip: 01234
For PHP < 5.3 the following adapted code can be used:
function expand2($str, $vars) {
$regex = '/\%(\w+)/';
$eval = substr($str, 0, 1) == '^';
$res = preg_replace_callback($regex, array(new Helper($vars, $eval),'callback'), $str);
if($eval) {
ob_start();
$expr = substr($res, 1);
if(eval('$res = ' . $expr . ';')===false) {
ob_end_clean();
die('Not a correct PHP-Expression: '.$expr);
}
ob_end_clean();
}
return $res;
}
class Helper {
var $vars;
var $eval;
function Helper($vars,$eval) {
$this->vars = $vars;
$this->eval = $eval;
}
function callback($matches) {
if(isset($this->vars[$matches[1]])) {
$expanded = expand($this->vars[$matches[1]], $this->vars);
if($this->eval) {
// Special handling since $str is going to be evaluated ..
if(!is_numeric($expanded) || (substr($expanded . '', 0, 1)==='0'
&& strpos($expanded . '', '.')===false)) {
$expanded = "'$expanded'";
}
}
return $expanded;
} else {
// Variable does not exist in $vars array
if($this->eval) {
return 'null';
}
return $matches[0];
}
}
}
I now have written an evaluator for your code, which addresses the circular reference problem, too.
Use:
$expression = new Evaluator($vars);
$vars['a'] = 'This is a string';
// ...
$vars['circular'] = '%ralucric';
$vars['ralucric'] = '%circular';
echo $expression->evaluate('%circular');
I use a $this->stack to handle circular references. (No idea what a stack actually is, I simply named it so ^^)
class Evaluator {
private $vars;
private $stack = array();
private $inEval = false;
public function __construct(&$vars) {
$this->vars =& $vars;
}
public function evaluate($str) {
// empty string
if (!isset($str[0])) {
return '';
}
if ($str[0] == '^') {
$this->inEval = true;
ob_start();
eval('$str = ' . preg_replace_callback('#%(\w+)#', array($this, '_replace'), substr($str, 1)) . ';');
if ($error = ob_get_clean()) {
throw new LogicException('Eval code failed: '.$error);
}
$this->inEval = false;
}
else {
$str = preg_replace_callback('#%(\w+)#', array($this, '_replace'), $str);
}
return $str;
}
private function _replace(&$matches) {
if (!isset($this->vars[$matches[1]])) {
return $this->inEval ? 'null' : '';
}
if (isset($this->stack[$matches[1]])) {
throw new LogicException('Circular Reference detected!');
}
$this->stack[$matches[1]] = true;
$return = $this->evaluate($this->vars[$matches[1]]);
unset($this->stack[$matches[1]]);
return $this->inEval == false ? $return : '\'' . $return . '\'';
}
}
Edit 1: I tested the maximum recursion depth for this script using this:
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEF'; // GHIJKLMNOPQRSTUVWXYZ
$length = strlen($alphabet);
$vars['a'] = 'Hallo World!';
for ($i = 1; $i < $length; ++$i) {
$vars[$alphabet[$i]] = '%' . $alphabet[$i-1];
}
var_dump($vars);
$expression = new Evaluator($vars);
echo $expression->evaluate('%' . $alphabet[$length - 1]);
If another character is added to $alphabet maximum recursion depth of 100 is reached. (But probably you can modify this setting somewhere?)
I actually just did this while implementing a MVC framework.
What I did was create a "find-tags" function that uses a regular expression to find all things that should be replaced using preg_match_all and then iterated through the list and called the function recursively with the str_replaced code.
VERY Simplified Code
function findTags($body)
{
$tagPattern = '/{%(?P<tag>\w+) *(?P<inputs>.*?)%}/'
preg_match_all($tagPattern,$body,$results,PREG_SET_ORDER);
foreach($results as $command)
{
$toReturn[] = array(0=>$command[0],'tag'=>$command['tag'],'inputs'=>$command['inputs']);
}
if(!isset($toReturn))
$toReturn = array();
return $toReturn;
}
function renderToView($body)
{
$arr = findTags($body);
if(count($arr) == 0)
return $body;
else
{
foreach($arr as $tag)
{
$body = str_replace($tag[0],$LOOKUPARRY[$tag['tag']],$body);
}
}
return renderToView($body);
}

Categories