OO PHP Array values are lost or missing - php

I'm relatively new to OO PHP, and frankly PHP in general. I have a class that I assign the array values in the constructor. However, when I access the array later, it is telling me that the array is null. Any ideas how this is going out of scope?
class SentenceContentContainer {
public $strSentence; //theSentence entered
public $arrayOfWords = []; //words in the sentence
private $num_words_in_sentence;
function __construct($strSentence)
{
$this->strSentence = $strSentence;
$arrayOfWords = explode(" ", $strSentence); //get the array of words in the string
$num_words_in_sentence = count($arrayOfWords); //count elements in the sentence
}
function sortHighestLetterRepeaterOfSentence()
{
usort($arrayOfWords, "compare"); //says parameter 1 is null
}
...
}
This is accessed from:
<html>
<head><title>PHP Code</title></head>
<body>
<?php
include "classes.php";
//process the data input
$post_string = implode("",$_POST); //change post array to string
// instantiate 1 of 2 objects
$sentenceCC = new SentenceContentContainer($post_string);
call_user_method("sortHighestLetterRepeaterOfSentence",$sentenceCC);
?>
<form method="post" action="">
<input type="text" name="value">
<input type="submit">
</form>
</body>
</html>
When I tried adding this->arrayOfWords in the Sentence contructor, it said it was a syntax issue.
I wonder if the issue is that somehow it's running the call_user_method even though I haven't hit submit yet in the form, after entering the sentence? I wouldn't think it would have gotten there yet?
Added: When I invoke the script in the browser, before I hit submit in the form, is when I see the warning message.
Added Also: Maybe I need to check that $arrayOfWords is not null or something in sortHighestLetterRepeaterOfSentence? I tried adding a check for null, but It's saying Undefined variable arrayOfWords where I test it for != null. I was also considering isset, but it's unclear that this would fix it.

$arrayOfWords is a variable that only exists inside the __construct function.
$this->arrayOfWords is a private class variable that exists in any method of the class and has a different value per-instance.
P.S. Why are you using call_user_method? This function is deprecated (and I think removed in PHP 7). Just a quick note, if you saw that in a tutorial, you should consider a new tutorial as that one's gonna be outdated.
You can just do:
$sentenceCC->sortHighestLetterRepeaterOfSentence()
If you must, you can use call_user_func instead:
call_user_func([$sentenceCC, 'sortHighestLetterRepeaterOfSentence']);

Yes this code will execute even if form is not submitted.
I think your should check $_POST variable and allow to run your code only
if (count( $_POST ))

Related

PHP object class not getting the submit field value

When I print the $letter variable, I am not getting the correct value. It always coming 0.
index.php
<form method="get" class="txtweb-form" action="index.php">
Guess a letter: <input type="text" name="txtweb-message" />
<input type="submit" value="submit" name="guess" />
</form>
<?php
$params = (object) $_REQUEST;
//print_r($params);
if (isset($params->guess)) {
$letter = $params->txtweb-message;
echo $letter;exit;
}
?>
You need to probably use _ instead of - in input name. - is not a valid character in PHP variable of property names.
What is actually happening is this:
$letter = $params->txtweb - message; // a subtraction operation
You end up subtracting an unset constant message from an unset object property $params->txtweb. Thus you get 0.
You can keep - in input name but you should use $_REQUEST['txtweb-message'] or $_GET['txtweb-message'] (without casting to object) to retrieve the value.
There really is no reason whatsoever to cast the superglobal array to an object, and this is what introduced your issue.
An additional note here. You really should be developing with error reporting turned on. That operation shown above would have resulted in two warnings showing up, which could have helped you understand what is happening.
why are you casting into an object?
wouldn't treating it as an array be easier like
<?php
$params = $_REQUEST;
if (isset($params["guess"])) {
$letter = $params["txtweb-message"];
echo $letter;exit;
}
?>

PHP isset not working properly on form, with loops and arrays

This is honestly the most finicky and inept language I've ever coded in. I'll be glad when this project is good and over with.
In any case I have to us PHP so here's my question.
I have an Array named $form_data as such:
$form_data = array
('trav_emer_med_insur',
'trav_emer_single',
'trav_emer_single_date_go',
'trav_emer_single_date_ba',
'trav_emer_annual',
'trav_emer_annual_date_go',
'trav_emer_extend',
'trav_emer_extend_date_go',
'trav_emer_extend_date_ef',
'trav_emer_extend_date_ba',
'allinc_insur',
'allinc_insur_opt1',
'allinc_single_date_go',
'allinc_single_date_ba',
'allinc_insur_opt2',
'allinc_annual_date_go',
'allinc_annual_date_ba',
'cancel_insur',
'allinc_annual_date_go',
'allinc_annual_date_ba',
'visitor_insur',
'country_select',
'visitor_supervisa',
'visitor_supervisa_date_go',
'visitor_supervisa_date_ba',
'visitor_student',
'visitor_student_date_go',
'visitor_student_date_ba',
'visitor_xpat',
'visitor_xpat_date_go',
'visitor_xpat_date_ba',
'txtApp1Name',
'txtApp2Name',
'txtApp1DOB',
'txtApp2DOB',
'txtApp1Add',
'txtApp1City',
'selprov',
'txtApp1Postal',
'txtApp1Phone',
'txtApp1Ext',
'txtApp1Email',
'conpref', );
These are the names of name="" fields on an HTML form. I have verified that ALL names exist and have a default value of '' using var_dump($_POST).
What I want to do is very simple, using the $form_data as reference do this:
create a new array called $out_data which can handle the data to display on a regurgitated form.
The structure of $out_data is simple the key will be the name of the element from the other array $out_data[txtApp1Name] for example, and then the value of that key will be the value.
Now what I want is to first check to see if every name="" is set or not, to eliminate errors and verify the data. Then regardless of whether it is set or not, create its placeholder in the $out_data array.
So if $_POST[$form_data[1]] (name is 'trav_emer_single') is not set create an entry in $out_data that looks like this $out_data([trav_emer_single] => "NO DATA")
If $_POST[$form_data[1]] (name is 'trav_emer_single') is set create and entry in $out_data that looks like this: $out_data([trav_emer_single] => "whatever the user typed in")
I have tried this code:
$out_data = array();
$count = count($form_data);
for( $i = 0; $i < $count; $i++ )
{
if(!isset($_POST[$form_data[$i]])) {
$out_data[$form_data[$i]] = "NO_DATA";
}
else {
$out_data[$form_data[$i]] = $_POST[$form_data[$i]];
}
}
Now this code technically is working, it is going through the array and assigning values, but it is not doing so properly.
I have hit submit on the form with NOTHING entered. Therefore every item should say "NO_DATA" on my regurgitated output (for user review), however only some items are saying it. All items I have confirmed have name="" and match the array, and have nothing entered in them. Why is "NO_DATA" not being assigned to every item in the array?
Also of note, if I fill in the form completely $out_data is fully and correctly populated. What is the problem with !isset? I've tried doing $_POST[$form_data[$i]] == '' which does put no_data in every instance of no data, however it throws an 'undefined index' warning for every single item on the page whether I write something in the box or not.
Really I just want to know WTF is going on, the dead line for this project is closing fast and EVERY step of the PHP gives me grief.
As far as I can tell by reading around my code is valid, but refuses to execute as advertised.
If you need more code samples please ask.
Really befuddled here, nothing works without an error, help please.
Thanks
-Sean
Instead of checking !isset(), use empty(). If the form posts an empty string, it will still show up in the $_POST as an empty string, and isset() would return TRUE.
I've replaced your incremental for loop with a foreach loop, which is almost always used in PHP for iterating an array.
$out_data = array();
foreach ($form_data as $key) {
if(empty($_POST[$key])) {
$out_data[$key] = "NO_DATA";
}
else {
$out_data[$key] = $_POST[$key];
}
}
PHP's isset returns TRUE unless the variable is undefined or it is NULL. The empty string "" does not cause it to return FALSE. empty() will do exactly what you need, though.
http://php.net/manual/en/function.isset.php
isset() will return FALSE if testing a variable that has been set to
NULL. Also note that a NULL byte ("\0") is not equivalent to the PHP
NULL constant.
Returns TRUE if var exists and has value other than NULL, FALSE
otherwise.

how arguments are passed to codeigniter method

I have a method in a codeigniter controller which is sometimes called through the url and sometimes called internally from another method of the controller. When I call it internally I pass an array of arguments. Simplified version of method:
(within a controller)
function get_details($args='') {
if (isset($args['first_name']))
{
$first_name = $args['first_name'];
}
else
{
$first_name = $this->uri->segment(3);
}
... do some other stuff ...
}
The method is either called as:
<domain>/<controller>/get_details/abcd/efgh
or from another function of the controller as:
$this->get_details(array('first_name'=>'abcd', 'last_name'=>'efgh'));
I was expecting that when the method was called through the url, isset($args['first_name']) would be false, however it seems that called in this way the argument is there. I tried printing a couple of things and this is what I got:
print_r($args) ----> abcd
echo($args['first_name']) ----> a
echo($args['whatever_index_I_use']) ----> a
It seems like the third parameter of the url is being passed into the method (by codeigniter?), but can't work out why the array indexes seem to be set, all I can think is that php is converting the string to an int, so $args['whatever_index_I_use'], becomes $args[0]??
Not sure if this is a codeigniter thing or me missing a subtlety of php.
Much appreciate anyone who can explain what's going on.
Thanks.
I don't know if this is a bug or a expected behavior, but in the Strings docs there's a comment that show exactly what are you experiencing. If you use a text and index of the string it will return the first char. To avoid it, check first if the argument is an array or a string:
if(is_array($args)) {
echo($args['first_name']);
}
To complete #SérgioMichels answer, the reason for that is because PHP is expecting an integer as the given index. When you give it a string, PHP will cast the string into an integer, and assuming that the string does not start with a number, type casting will return 0 otherwise, it will return the leading number.
$str = 'abcdefghi';
var_dump($str['no_number']); // Outputs: string(1) "a"
var_dump($str['3something']); // Outputs: string(1) "d"
To specifically answer your question - this will solve your bug:
function get_details($args='')
{
if (is_array($args))
{
$first_name = $args['first_name'];
}
else
{
$first_name = $this->uri->segment(3);
}
... do some other stuff ...
}
But you have some issues with your code. Firstly you state that you call the method as
<domain>/<controller>/get_details/abcd/efgh
but you dont accept the "efgh" variable in your controller. To do this, you need to change the function to
function get_details($first, $last)
in which case you can now just call the function as
$this->get_details('abcd', 'efgh');
and now you dont even need to test for arrays etc, which is a better solution IMO.
If you decide to stick with arrays, change:
$first_name = $this->uri->segment(3);
to
$first_name = $args;
because by definition - $args IS The 3rd URI segment.

PHP $_POST[$variable] in an included file, doesn't recognize the $variable and creates an error message

I would like to use "dynamic" $_POSTs, I don't know if I am using the right term but in other words I would like to use for example $_POST[$dynamic_variable] in a function that is in an included file. Because the $dynamic_variable isn't recognized or because I can't use $_POST[something] in included files it doesn't work and I get an error message like Undefined variable: lastname in filename.php.
What is the safe to way to use $_POSTs in included files and when the $_POST[name] is variable?
Thank you!
///// updated - piece of code ///////
[code.php]
include("functions.php");
$test_arr = array(
"10|field_name1|500",
"20|field_name2|750",
...
);
checkForm($test_arr);
[functions.php]
function checkForm($test_arr) {
foreach ($test_arr as $test) {
$test_details = explode("|", $test);
$field_name = $test_details[1];
echo $_POST[$field_name];
}
}
The $_POST array is available in all included PHP files. Normally, the $dynamic_variable is also available, if you do it like so:
$dynamic_variable = 'test';
include('include.php');
// in include.php:
echo $_POST[$dynamic_variable];
But when declaring the $dynamic_variable inside a function or class, you don't have access to it outside. You could also declare it as global or hand it over as a parameter. Please also read the documentation about variable scope.
I would not write if it is smart to use globals like that or not.
Your problem is you tried to access a variable which does not exists, as the error message said.
To avoid the error message, you can do:
if(isset($_POST[$your_var_name]){
//do something with $_POST[$your_var_name]
}

Find the name of a calling var

Anyone has an idea if this is at all possible with PHP?
function foo($var) {
// the code here should output the value of the variable
// and the name the variable has when calling this function
}
$hello = "World";
foo($hello);
Would give me this output
varName = $hello
varValue = World
EDIT
Since most people here 'accuse' me of bad practices and global variables stuff i'm going to elaborate a little further on why we are looking for this behaviour.
the reason we are looking at this kind of behaviour is that we want to make assigning variables to our Views easier.
Most of the time we are doing this to assign variables to our view
$this->view->assign('products', $products);
$this->view->assign('members', $members);
While it would be easier and more readable to just be able to do the following and let the view be responsible to determining the variable name the assigned data gets in our views.
$this->view->assign($products);
$this->view->assign($members);
Short answer: impossible.
Long answer: you could dig through apd, bytekit, runkit, the Reflection API and debug_backtrace to see if any obscure combination would allow you to achieve this behavior.
However, the easiest way is to simply pass the variable name along with the actual variable, like you already do. It's short, it's easy to grasp, it's flexible when you need the variable to have a different name and it is way faster than any possible code that might be able to achieve the other desired behavior.
Keep it simple
removed irrelevant parts after OP edited the question
Regardless of my doubt that this is even possible, I think that forcing a programmer on how to name his variables is generally a bad idea. You will have to answer questions like
Why can't I name my variable $arrProducts instead of $products ?
You would also get into serious trouble if you want to put the return value of a function into the view. Imagine the following code in which (for whatever reason) the category needs to be lowercase:
$this->view->assign(strtolower($category));
This would not work with what you're planning.
My answer therefore: Stick to the 'verbose' way you're working, it is a lot easier to read and maintain.
If you can't live with that, you could still add a magic function to the view:
public function __set($name, $value) {
$this->assign($name, $value);
}
Then you can write
$this->view->product = $product;
I don't think there is any language where this is possible. That's simply not how variables work. There is a difference between a variable and the value it holds. Inside the function foo, you have the value, but the variable that held the value is not available. Instead, you have a new variable $var to hold that value.
Look at it like this: a variable is like a bucket with a name on it. The content (value) of the variable is what's inside the bucket. When you call a function, it comes with its own buckets (parameter names), and you pour the content of your bucket into those (well, the metaphor breaks down here because the value is copied and still available outside). Inside the function, there is no way to know about the bucket that used to hold the content.
What you're asking isn't possible. Even if it was, it would likely be considered bad practice as its the sort of thing that could easily get exploited.
If you're determined to achieve something like this, the closest you can get would be to pass the variable name as a string and reference it in the function from the $GLOBALS array.
eg
function this_aint_a_good_idea_really($var) {
print "Variable name: {$var}\n";
print "Variable contents: {$GLOBALS[$var]}\n";
}
$hello="World";
this_aint_a_good_idea_really('hello');
But as I say, that isn't really a good idea, nor is it very useful. (Frankly, almost any time you resort to using global variables, you're probably doing something wrong)
Its not impossible, you can find where a function was invoked from debug_backtrace() then tokenize a copy of the running script to extract the parameter expressions (what if the calling line is foo("hello $user, " . $indirect($user,5))?),
however whatever reason you have for trying to achieve this - its the wrong reason.
C.
Okay, time for some ugly hacks, but this is what I've got so far, I'll try to work on it a little later
<?php
class foo
{
//Public so we can test it later
public $bar;
function foo()
{
//Init the array
$this->bar = array();
}
function assign($__baz)
{
//Try to figure out the context
$context = debug_backtrace();
//assign the local array with the name and the value
//Alternately you can initialize the variable localy
//using $$__baz = $context[1]['object']->$__baz;
$this->bar[$__baz] = $context[1]['object']->$__baz;
}
}
//We need to have a calling context of a class in order for this to work
class a
{
function a()
{
}
function foobar()
{
$s = "testing";
$w = new foo();
//Reassign local variables to the class
foreach(get_defined_vars() as $name => $val)
{
$this->$name = $val;
}
//Assign the variable
$w->assign('s');
//test it
echo $w->bar['s'];
}
}
//Testrun
$a = new a();
$a->foobar();
impossible - the max. ammount of information you can get is what you see when dumping
debug_backtrace();
Maybe what you want to do is the other way around, a hackish solution like this works fine:
<?php
function assign($val)
{
global $$val;
echo $$val;
}
$hello = "Some value";
assign('hello');
Ouputs: Some value
What you wish to do, PHP does not intend for. There is no conventional way to accomplish this. In fact, only quite extravagant solutions are available. One that remains as close to PHP as I can think of is creating a new class.
You could call it NamedVariable, or something, and as its constructor it takes the variable name and the value. You'd initiate it as $products = new NamedVariable('products', $productData); then use it as $this->view->assign($products);. Of course, your declaration line is now quite long, you're involving yet another - and quite obscure - class into your code base, and now the assign method has to know about NamedVariable to extract both the variable name and value.
As most other members have answered, you are better off suffering through this slight lack of syntactic sugar. Mind you, another approach would be to create a script that recognizes instances of assign()'s and rewrites the source code. This would now involve some extra step before you ran your code, though, and for PHP that's silly. You might even configure your IDE to automatically populate the assign()'s. Whatever you choose, PHP natively intends no solution.
This solution uses the GLOBALS variable. To solve scope issues, the variable is passed by reference, and the value modified to be unique.
function get_var_name(&$var, $scope=FALSE) {
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = 'unique'.rand().'value';
$vname = FALSE;
foreach ($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
$testvar = "name";
echo get_var_name($testvar); // "testvar"
function testfunction() {
$var_in_function = "variable value";
return get_var_name($var_in_function, get_defined_vars());
}
echo testfunction(); // "var_in_function"
class testclass {
public $testproperty;
public function __constructor() {
$this->testproperty = "property value";
}
}
$testobj = new testclass();
echo get_var_name($testobj->testproperty, $testobj); // "testproperty"

Categories