I have inherited some old code and need to convert the create_function to an anonymous function. I have done that but since I cannot see the code in the anonymous function I do not know if it equals the code in the former create_function.
Here is the code and my question is: is 'my translation' equal to the 'original code'?
public static function makePhpVdtorFromRegex($regex, $match = TRUE)
{
//original code
$s = 'return '.($match?'':'0 == ').'preg_match(\'/'.addslashes($regex).'/\',$v);';
return create_function('$v', $s);
// my translation
return function($v) use ($regex, $match) {
return ($match?'':'0 == ').preg_match('/'.addslashes($regex).'/',$v);
};
}
I believe makePhpVdtorFromRegex stands for 'Make PHP Validator From Regex'. The problem in validating this is I am not sure where the actual validator is used as this anonymous function is stored in an array which is used to validate input at some later time doing form input validation.
Because $regex and $match only exist within makePhpVdtorFromRegex() they will not be available when the validator is ultimately run, right? So I suspect my translation is not going to work?
To mimic the original behaviour, you should be able to replace it with (for testing purposes, I turned the method into a function):
function makePhpVdtorFromRegex($regex, $match = true) {
if ($match) {
return function($value) use ($regex) {
return preg_match('/'.addslashes($regex).'/', $value);
};
}
return function($value) use ($regex) {
// Same as '0 == preg_match(...)' from original code
return !preg_match('/'.addslashes($regex).'/', $value);
};
}
$validator = makePhpVdtorFromRegex('^[a-z]+$');
// Check if something matches
var_dump($validator('abc')); // true
// Check if something doesn't match
$validator = makePhpVdtorFromRegex('^[a-z]+$', false);
var_dump($validator('123')); // true
If you've the chance to look into the actual form validation later on & maybe even take control of the regular expressions themselves, you could rewrite this code to something much simpler, like:
function getRegexValidator() {
return function($regex, $value) {
return preg_match($regex, $value);
};
}
$validator = getRegexValidator();
// Check if something matches
var_dump($validator('/^[a-z]+$/', 'abc')); // true
// Check if something doesn't match
var_dump(!$validator('/^[a-z]+$/', '123')); // true
Related
I have written a custom translation function for Laravel, which first checks a configuration variable to see whether to use Laravel's default __() function or my custom trans() function.
Here's my function:
function t($key, $replace = [], $locale = null)
{
$source = Config::get('translate.source');
if ($source == 'database') {
return trans($key, $replace, $locale);
} else {
return __($key, $replace, $locale);
}
}
However, for speed purposes, I don't want the if condition to run reach time I call the t() function, but only on the first call.
Any ideas?
You want to set a variable in the class and refer to that. So, create a variable databaseSource:
private $databaseSource = false;
You then want a method that will change the boolean:
function updateSource()
{
$source = Config::get('translate.source');
if ($source == 'database') {
$this->databaseSource = true;
}
$this->databaseSource = false;
}
You can then use this piece of functionality over and over via accessing the variable instead of getting the source every time you need it.
E.g. if ($databaseSource) { ... }
I am having trouble using a variable generated in one function, as a variable in a second function.
The Problem:
I get Notice: Undefined variable: parameter in the validate function, on the line:
$this->$methodName($item,$value,$parameter) OR $valid=false;
When the function call for splitRulesAndParameters is simply replaced with the code within the function, the problem goes away.
The Scenario:
The following two functions are both within the Validator class, the first, validate, makes use of the second, splitRulesAndParameters
Here is the validate function:
public function validate($data, $rules)
{
$valid= true;
foreach($rules as $item=>$ruleSet)
{
$ruleSetArray=explode('|',$ruleSet);
foreach($ruleSetArray as $rule)
{
$this->splitRulesAndParameters($rule);
$methodName='validate'.ucfirst($rule);
$value = isset($data[$item]) ? $data[$item] : NULL;
if(method_exists($this, $methodName))
{
$this->$methodName($item,$value,$parameter) OR $valid=false;
}
}
}
return $valid;
}
And here is the splitRulesAndParameters function
public function splitRulesAndParameters($rule)
{
$position = strpos($rule, ':');
if($position !==false)
{
$parameter = substr($rule,$position + 1);
$rule = substr($rule,0,$position);
}
else
{
$parameter='';
}
}
Seeing as the problem goes away if you "inline" the code in splitRulesAndParameters, I suspect the $parameters variable is used in that method. If so, simply have that method return the value of this variable, and assign it to a variable local to the validate method you've posted here:
$parameters = $this->splitRulesAndParameters($rule);
After adding this to the splitRulsAndParameters method:
return $parameters;
The method itself also modifies the $rule value. Again: this $rule variable is local to each method. It may have the same name, but the value is a copy. Any changes you make to $rule in splitRulesAndParameters is not reflected by $rule in your validate method. If I were you, I'd write:
public function splitRulesAndParameters($rule)
{
$position = strpos($rule, ':');
if($position !==false)
{
return array(
'parameter' => substr($rule, $position+1),
'rule' => substr($rule, 0, $position)
);
}
return array(
'parameter' => null,//no param == null, IMO, change to '' if you want
'rule' => $rule
);
}
Then, to change the variables in validate:
$split = $this->splitRulesAndParameters($rule);
$rule = $split['rule'];
$parameter = $split['parameter'];
That ought to do it.
Side-note:
You seem to be validating everything that needs validating, even if the first validation failed. If I were you, I'd change this fugly statement:
$this->$methodName($item,$value,$parameter) OR $valid=false;
To a more efficient:
if (!$this->{$methodName}($item, $value, $parameter))
return false;//if validation fails, return false
That stops any further valiation from being executed: if one value is invalid, then just stop there. To continue is pointless, because the data-set is not entirely valid anyway.
Bonus:
Using a colon to separate the method name, and some parameter(s) does allow you to specify multiple params, too, and it allows you to simplify the splitRulesAndParameters some more:
protected function splitRulesAndParameters($rule)
{
$all = explode(':', $rule);
return array(
'rule' => array_shift($all),//removes first element in array
'params' => $all//rest of the array
);
}
Tweak this a little to better suite your needs
You can't just use a variable from inside a function in another function. You have to return the variable $parameter. Add a return statement to the end of splitRulesAndParameters and store the result in a variable inside validate ($parameter = $this->spli...).
You actually have two problems here, because you change the &rule variable inside your function, but you are passing it by reference. So after the fucntion is done the $rule variable is the same as it was before.
The way to solve this in the manner you are doing it right now would be to change the function to:
public function splitRulesAndParameters(&$rule)
{
$position = strpos($rule, ':');
if($position !==false)
{
$parameter = substr($rule,$position + 1);
$rule = substr($rule,0,$position);
}
else
{
$parameter='';
}
return $parameter;
}
and change the line
$this->splitRulesAndParameters($rule);
to
$parameter = $this->splitRulesAndParameters($rule);
This does not work
$check["pattern"] = "/correct/";
$callback = "function ($m) { return ucfirst($m[0]);}";
echo preg_replace_callback($check["pattern"],$callback,"correct" );
output: correct
This works
$check["pattern"] = "/correct/";
echo preg_replace_callback($check["pattern"],function ($m) { return ucfirst($m[0]);},"correct" );
output: Correct
Why, and how to make it work with the function stored inside a var? :)
Why would you want to do that? I see no reason to store the function inside a variable, to be honest. Nevertheless, if you really want to do this, take a look at create_function:
<?php
$check["pattern"] = "/correct/";
$callback = create_function('$m', 'return ucfirst($m[0]);');
echo preg_replace_callback( $check['pattern'], $callback, "correct" );
// Output: "Correct"
If you do a var_dump on $callback = "function ($m) { return ucfirst($m[0]);}"; the result is a string. In the working situation you pass a Closure (anonymous function) as callback.
The manual is clear: a Closure is allowed, if you pass a string, it must be the name of a function.
i have a problem with insensitive array_keys and in_array ...
I developing a translator, and i have something like this:
$wordsExample = array("example1","example2","example3","August","example4");
$translateExample = array("ejemplo1","ejemplo2","ejemplo3","Agosto","ejemplo4");
function foo($string,$strict=FALSE)
{
$key = array_keys($wordsExample,$string,$strict);
if(!empty($key))
return $translateExample[$key[0]];
return false;
}
echo foo('example1'); // works, prints "ejemplo1"
echo foo('august'); // doesnt works, prints FALSE
I tested with in_array and same result...:
function foo($string,$strict=FALSE)
{
if(in_array($string,$wordsExample,$strict))
return "WOHOOOOO";
return false;
}
echo foo('example1'); //works , prints "WOHOOOOO"
echo foo('august'); //doesnt works, prints FALSE
Create the array and find the keys with with strtolower:
$wordsExample = array("example1","example2","example3","August","example4");
$lowercaseWordsExample = array();
foreach ($wordsExample as $val) {
$lowercaseWordsExample[] = strtolower($val);
}
if(in_array(strtolower('august'),$lowercaseWordsExample,FALSE))
return "WOHOOOOO";
if(in_array(strtolower('aUguSt'),$lowercaseWordsExample,FALSE))
return "WOHOOOOO";
Another way would be to write a new in_array function that would be case insensitive:
function in_arrayi($needle, $haystack) {
return in_array(strtolower($needle), array_map('strtolower', $haystack));
}
If you want it to use less memory, better create the words array using lowercase letter.
I created a small function a while to get, to test clean-URLs as they could be uppercase, lowercase or mixed:
function in_arrayi($needle, array $haystack) {
return in_array(strtolower($needle), array_map('strtolower', $haystack));
}
Pretty easy this way.
I was basically playing around with OOP and was creating a way to validate and sanitise input when I started to run into problems sanitising and then performing further validation. What I'm looking for is to take the posted $_POST['name'] data, sanitise the input to remove any numbers and validate that the data left is neither null or numeric characters.
But I cant get the sanitised input saved to $sanitised, It seems to be empty, but when I replace
$sanitised=$fv->noNumbers($_POST['name']);
with
$sanitised=preg_replace('/[0-9]/', '', $_POST['name']);
everything works fine, so I think I'm messing up something in this $sanitised variable.
I wanna learn so either a solution to this or a "you're an idiot and doing it all wrong" would be much appreciated.
<?php
class formSanitise {
public function noNumbers($value) {
$value = preg_replace('/[0-9]/', '', $value);
}
public function isEmpty($value) {
return (!isset($value) || trim($value) == '') ? true : false;
}
public function isAlpha($value) {
return preg_match('/[^a-z]/i', $value) ? false : true;
}
?>
processor.php
<?php
include('class.formSanitise.php');
$fv = new formSanitise();
$sanitised= $fv->noNumbers($_POST['name']);
if ($fv->isEmpty($sanitised)) {
$fv->addError('Name', 'Please enter something');
}
if (!$fv->isAlpha($sanitised)) {
$fv->addError('Name', 'Please enter your name');
}
?>
You'll either need to create a return in noNumbers or pass $value by reference.
Return method:
public function noNumbers($value) {
return preg_replace('/[0-9]/', '', $value);
}
Reference
public function noNumbers(&$value) {
$value = preg_replace('/[0-9]/', '', $value);
}
returning a value means that $value is an entirely different variable, and will be assigned to $sanitized when it's returned from the function. Passing by reference means that $value is the exact same variable as the one you passed to noNumbers and as such, anything that happens to the variable inside the function will happen to the variable that has been passed in.
In the above code snippet the function noNumbers does not return any value.The argument passed to the function has a scope within that function only and in order to make that value available to calling function there must be a return statement within function which will return the value to the calling function .Alternatively you can pass the value to function by reference .