Recently have been reviewing how classes work in PHP. I have stumbled across this code and I am trying to understand why WAMP is giving me notices as opposed to my host.
$settings['ip_forwarded_check'] = 1;
function get_ip()
{
$ip = 0;
if(!preg_match("#^(10|172\.16|192\.168)\.#", $_SERVER['REMOTE_ADDR']))
{
$ip = $_SERVER['REMOTE_ADDR'];
}
if($settings['ip_forwarded_check'])
{
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
preg_match_all("#[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}#s", $_SERVER['HTTP_X_FORWARDED_FOR'], $addresses);
}
elseif(isset($_SERVER['HTTP_X_REAL_IP']))
{
preg_match_all("#[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}#s", $_SERVER['HTTP_X_REAL_IP'], $addresses);
}
if(is_array($addresses[0]))
{
foreach($addresses[0] as $key => $val)
{
if(!preg_match("#^(10|172\.16|192\.168)\.#", $val))
{
$ip = $val;
break;
}
}
}
}
if(!$ip)
{
if(isset($_SERVER['HTTP_CLIENT_IP']))
{
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
}
return $ip;
}
The errors I will get are:
Notice: Undefined variable: settings in
Notice: Undefined variable: addresses in
I can fix all the problems by adding a "global: $settings; global $addresses;" but I was wondering how to prevent this? I know many claim I should not use globals in functions and so that leads me to wonder the correct way to go about this. I would also like to know why one host will show me warnings/notices and the other does not? I do not have the notices turned off for my host.
Both your problems stem from the fact that you are using uninitialized variables. If you write
$foo = "abc";
in your code, then, if $foo was not existent before, it will be created and initialized. However, if you do something like this:
$settings['ip_forwarded_check'] = 1;
then you try to refer an item of an associated array, which was never created. Let's create it:
$settings = array();
$settings['ip_forwarded_check'] = 1;
You will also need to initialize $addresses, but I do not know about your task enough to give you any advice about the way you should initialize it.
Error reporting is probably switched off on your server, which should be the reason you do not see the error messages there.
Related
I need to know if there is a better way to avoid Call to a member function xxxx() on null
currently I'm coding as follows but it is cumbersome.
if($event->getForm()
&& $event->getForm()->getParent()
&& $event->getForm()->getParent()->getParent()
&& $event->getForm()->getParent()->getParent()->getData()
&& $event->getForm()->getParent()->getParent()->getData()->getComponente()
){
$componente = $event->getForm()->getParent()->getParent()->getData()->getComponente();
$formModifier($event->getForm(), $componente, $defaultComponente);
}
In PHP 7 this is actually a catchable Error (if you're using hhvm it's a regular Exception):
try {
$componente = $event->getForm()->getParent()->getParent()->getData()->getComponente();
} catch (\Error $e) {
$componente = null;
}
if ($componente !== null) {
$formModifier($event->getForm(), $componente, $defaultComponente);
}
In PHP 5 there is a workaround using intermediate variables and the and keyword instead of &&:
if (
$f = $event->getForm() and
$p = $f->getParent() and
$p2 = $p->getParent() and
$d = $p2->getData() and
$componente = $d->getComponente()
) {
$formModifier($f, $componente, $defaultComponente);
}
If you use && instead of and you'll get "undefined variable" notices and this workaround won't work.
Working examples: https://3v4l.org/0S6ps
no there is no way, but at least you can do some performance improvement
$form = $event->getForm();
if(!$form){
//do error handling
return;
}
$parent = $form->getParent();
if(!$parent){
//do error handling
return;
}
$p_parent = $parent->getParent();
if(!$p_parent){
//do error handling
return;
}
$data = $p_parent->getData();
if(!$data){
//do error handling
return;
}
$component = $data->getComponente();
...
this way you call each function only once and you can do better error handling
I think this is a great example of a bad code. By having a code like this you're breaking several rules and making your life much harder than it should be.
Your code is rigid, fragile, hard to understand and maintain etc.
Simpler is ALWAYS better.
If you can't make your $xx->getComponent() a proper object easily accessible without such ugly nested relationship, you should at least encapsulate the method into something appropriate and use that instead, so if anything changes, you don't have to go full mental and change it all over the place.
This class seems strange in it's creation, but if you are not extracting these methods dynamically using __call(), you can use method_exists() in a loop inside a function, something similar to:
function getMethodChain($class,$arr = ['getForm','getParent','getParent','getData','getComponente'])
{
# First check the object is set
if(!is_object($class))
return false;
# Loop intended method chain
foreach($arr as $method) {
# Check if the method exists in the current class or passed already
$useClass = (!isset($classPass))? $class : $classPass;
# Check if the method exists in the current class
if(is_object($useClass) && method_exists($useClass,$method)) {
# Assign this class/method to use next in the loop
$classPass = $useClass->{$method}();
}
else
return false;
}
# Just send back
return (isset($classPass))? $classPass : false;
}
The use would be something like:
# This will either be the data you expect or false
$componente = getMethodChain($event);
I've been out of PHP programming for a while, but I'm almost sure I used to be able to write something like the following:
function checkData($data, $moreData) {
if ($foo != validate($data)) {
return false;
}
if ($bar != validate($moreData)) {
return false;
}
$result = "$foo" . "$bar";
return $result;
}
...where "$foo" and "$bar" haven't been set yet and where the "validate()" function either returns validated data, or returns false if validation fails.
I can't figure out where I'm going wrong, but that code (and variations of it) is throwing an "Undefined variable" error for $myVar.
What would be the correct syntax for this concept?
I think you meant a little bit different thing. Instead of
if ($foo != validate($data)) {
You've been using this
if (!$foo = validate($data)) {
What is happening there is:
1. Call validate function
2. Assign the result to variable
3. Check if condition for that variable.
It's kind of the same as
$foo = validate($data)
if(!$foo)
But as you can understand it's not recommended way of doing the things as it's hard to read and needs explanation(otherwise why do u ask it here, hehe)
PHP has become more strict over the years. You should always instantiate your variables. The following modifications should resolve your "undefined variable" issues:
function checkData($data, $moreData) {
$foo = $bar = null;
if (!$foo = validate($data)) {
return false;
}
if (!$bar = validate($moreData)) {
return false;
}
$result = "$foo" . "$bar";
return $result;
}
It isn't the conditional that is throwing the warning, but where you attempt to assign the non-existent variables to $result. Additionally, your conditionals are checking for comparison rather than assignment.
I am having a problem with PHP that's confusing to me
Namely: Notice: Undefined variable: _GET in /var/www/dd.lo/app/libraries/system/input.php on line 86
pops up when you call:
$this->input->get('test');
The function calls another function (If my approach is bad please do not be mad. I will be happy if you tell me how to do it correctly):
public function get ($index)
{
return $this->_getArray('_GET', $index);
}
here is the code of the private function:
private function _getArray ($array, $index)
{
if (isset(${$array}[$index]))
{
return ${$array}[$index];
}
else
{
return NULL;
}
}
The Input class provides convenient access to _POST, _GET, _COOKIE and _SERVER data and allows you to avoid type checking:
if (isset($_POST['name']))
{
$name = $_POST['name'];
}
else
{
$name = NULL;
}
Incidentally, it requests a page at http://dd.lo/?test=dgdsgsdgsdgsd (i.e. $_GET, I asked)
If you write var_dump($_GET); then there is the index 'test'.
Apologies for the English, but I don't speak or read your language (Russian?). This answer is based on Google translate's version of what you asked.
PHP's super globals ($_GET, $_POST, etc.) are special variables, and it looks like you can't use these variables with PHP's variable variable feature. For example, this works
$foo = ['Hello'];
$var_name = 'foo';
var_dump($$var_name);
The "variable variable" $$var_name expands as $'foo'/$foo, and the variable dumps correctly.
However, the following does not work
$var_name = '_GET';
var_dump($$var_name);
It appears that whatever magic scope variable variables live in, that scope doesn't include the super globals. You'll need to rethink your approach. One way you might do this is by accepting the actual array instead of a string that's it's name, and specifying a "by reference" parameter in your function to avoid any performance issues
function _getArray(&$array, $key)
{
if(!is_array($array)) { throw new Exception("Invalid argumnet!");}
if(array_key_exists($key, $array))
{
return $array[$key];
}
return NULL;
}
I get a strange PHP error after updating my php version to 5.4
This is my function
protected function create() {
//if (VBRIDGE_DEBUG)
//drupal_set_message(__CLASS__ .'::'.__METHOD__);
$path = $this->vbridge_root_path;
$path_vbridge = $path . '/' . VBridge::VBRIDGE_CLASS_PREFIX;
$subclass = $this->getClass();
foreach ($this->_objclass as $objclass) {
if (!$this->createObj($path, $objclass, $subclass)) {
$this->createObj($path_vbridge, $objclass);
}
}
if (self::getStatus()) {
return false;
}
// Set User Session Qookie
//$this->getUser()->setQookie($this->getQookie());
// Set User Session
$this->getUser()->setSession($this->getSession());
$this->getSession()->setQookie($this->getQookie());
//$this->getUser()->setAuth($this->getAuth());
// Set User Pass
$this->getUser()->setPass($this->getPass());
// Set Auth
$this->setAuthMethods();
$this->setAuthStorages();
//
foreach ($this->getConfig() as $config) {
if ($config['#type'] == '#class') {
//createObj($config['#name'], $config['#type'], $config['#class'], $config['#path'], $appData['#config']);
}
}
return true;
}
This is the line that gives
if ($config['#type'] == '#class') {
I've looked at similar questions but haven't figured out how to fix this. Any assistance would be helpful.
Edit: Yes, I did put wrong code up last night. I was very tired after trying to tangle with this.
The error message you've posted doesn't match the line of code you say it originates from. You should get a different error for that, specifically to do with only using variables by reference.
Your code should be
$accounts = user_load_multiple(array(), array('name' => $login));
$account = array_shift($account);
But Drupal already has a helper method for that, so you might as well use it:
$account = user_load_by_name($login);
Upon executing a script, sometimes the variable will be set, and sometimes it won't. The times that it isn't, I'm given a notice that the variable is not defined.
In efforts to clear the notice, I simple added the following code
if(!isset($var)) {
$var = NULL;
}
That works just as needed because it tests if the variable isn't already set so that we don't set something that we need to NULL. But in a file where there are over 60 variables that are of this case and more to come, I thought creating a simple function to do so would be easier. So I started with this:
function init($var) {
if(!isset($var)) {
return $var = NULL;
}
}
Obviously that doesn't work and is also riddled with errors that will annoy most programmers out there (such as the !isset() inside a function, not supplying a return statement in case the if statement is false, etc.) but that's just to give you the basic jist of what I need so in the code I can just call init($var); to test if the variable isn't already set, and then creates one and sets it to NULL to avoid the notice.
Is this even possible? To use a function to test if a variable is already set outside of the function? Thanks in advance :)
You can't use a function to check if a variable exists without it being initialized in the process of passing it to the function as an argument. You can, however, define an array of variable names your script requires then loop through them and check if they exist one by one. Such as:
foreach(array('username','userid','userrole','posts','dob','friends') as $var)
{
if(!isset($$var))$$var=NULL;
}
Edit: Simplifying user4035's approach, you could get the function down to:
<?php
function init(&$var){}
init($myVariable);
var_dump($myVariable);
Or even avoid a function altogether:
<?php
array(&$var1,&$var2,&$var3);//define several variables in one shot as NULL if not already defined.
var_dump($var1);
var_dump($var2);
var_dump($var3);
Another approach would be to use extract:
<?php
$defaults=array('username'=>NULL,'userid'=>0,'userrole'=>'guest','posts'=>0,'dob'=>0,'friends'=>array());
$userid=24334;
$username='bob';
$friends=array(2,5,7);
extract($defaults, EXTR_SKIP);
echo '<pre>';
print_r(
array(
'userid'=>$userid,
'username'=>$username,
'friends'=>$friends,
'userrole'=>$userrole,
'posts'=>$posts,
'dob'=>$dob)
);
echo '</pre>';
Another approach would be to temporarily disable error reporting:
<?php
$v=ini_get("error_reporting");
error_reporting(0);
echo 'One';
echo $doh;//Use an undefined variable
echo ' Two';
error_reporting($v);
I'd advise against this approach though because it is just hiding the errors rather than fixing them and will also hide errors worthy of your attention.
And my personal favorite would be to take advantage of namespaces.
Usually you'd put these into separate files but I put them into a single snippet for your convenience:
<?php
namespace //This is the global namespace
{
$config=array('production'=>0);
}
namespace MyScript
{
//Initialize all variables for our script
//anything not defined here will be inherited from the global namespace
$username=NULL;
$userid=NULL;
$userrole=NULL;
$posts=NULL;
$dob=NULL;
$friends=NULL;
}
namespace MyScript\Main
{
//Define only two variables for our script
//Everything else will be inherited from the parent namespace if not defined
$username='Ultimater';
$userid=4;
echo '<pre>';
print_r(
array(
'userid'=>$userid,
'username'=>$username,
'friends'=>$friends,
'userrole'=>$userrole,
'posts'=>$posts,
'dob'=>$dob,
'config'=>$config)
);
echo '</pre>';
}
If your intention is this:
if(variable is not set)
set variable to NULL
then it's quite easy to implement, using a reference:
function init(&$var) {
if(!isset($var)) {
$var = NULL;
}
}
Testing:
<?php
error_reporting(E_ALL);
function init(&$var) {
if(!isset($var)) {
$var = NULL;
}
}
init($x);
var_dump($x);
Output:
NULL