A riddle for me that is probably second nature to you....

Discussion in 'PHP' started by knightlightning55, Jan 19, 2013.

  1. #1
    Hi, my name is Pete and I currently am in school for web development. I am reading a PHP text book for one of my classes and cannot seem to figure out something about the script that is probably obvious and/or fundamental. Nonetheless, I cannot seem to figure it out.


    I realized that my first post was a little long winded and decided on a more compact code block.
    I believe this is a familiar piece of code for most people familiar with php, so it may make for a better example.
    Here is my question:

    How does $val get its value in the code block below?


    <?php
    // assume nothing is suspect
    $suspect = false;
    // create a pattern to locate suspect phrases
    $pattern = '/Content-Type:|Bcc:|Cc:/i';


    // function to check for suspect phrases
    function isSuspect($val, $pattern, &$suspect) {
    // if the variable is an array, loop through each element
    // and pass it recursively back to the same function
    if (is_array($val)) {
    foreach ($val as $item) {
    isSuspect($item, $pattern, $suspect);
    }
    } else {
    // if one of the suspect phrases is found, set Boolean to true
    if (preg_match($pattern, $val)) {
    $suspect = true;
    }
    }
    }

    We see 3 variables passed as arguments to the isSuspect() function. Both $pattern and $suspect have their values set explicitly, so we know what their value is and how they got it. However, it is not as clear to see where $val is getting its value.
    It seems to me that what is expected is that $val holds the value of the $_POST array. But the only place we see $val is where it is passed to the function: isSuspect($val, $pattern, $suspect) then we immediately start manipulating $val with a conditional statement and a foreach loop. As far as I can tell $val is not an array as it should be an undefined variable. Of course I am wrong as the code works just fine as written.

    I have come across this little puzzle too many times in studying php and I cannot figure it out. If anyone can shed some light on this for me I will appreciate it greatly!

    Thank you,

    Pete
     
    Last edited: Jan 19, 2013
    knightlightning55, Jan 19, 2013 IP
  2. EricBruggema

    EricBruggema Well-Known Member

    Messages:
    1,740
    Likes Received:
    28
    Best Answers:
    13
    Trophy Points:
    175
    #2
    $val is a list (array) of values to check to i assume.
     
    EricBruggema, Jan 20, 2013 IP
  3. Rukbat

    Rukbat Well-Known Member

    Messages:
    2,908
    Likes Received:
    37
    Best Answers:
    51
    Trophy Points:
    125
    #3
    
    <?php
    // assume nothing is suspect
    $suspect = false; //this is a global variable
    // create a pattern to locate suspect phrases
    $pattern = '/Content-Type:|Bcc:|Cc:/i'; //this is another global variable
    //If you want to use a global variable inside a function you have to declare it as a global inside the variable, which is not being done below
     
     
    // function to check for suspect phrases
    function isSuspect($val, $pattern, &$suspect) { //$suspect is being passed by reference, which is a fatal error
    /*
        $val, $pattern and $suspect are local variables
        they exist only within this function and have nothing to do
        with any variables of the same name that are declared outside this function
    */
    //this is where you'd declare
    global $val, $pattern, $suspect;
    //and you'd have to have declared $val outside the function
    // if the variable is an array, loop through each element
    // and pass it recursively back to the same function
    if (is_array($val)) {
    foreach ($val as $item) {
    isSuspect($item, $pattern, $suspect);
    }
    } else {
    // if one of the suspect phrases is found, set Boolean to true
    if (preg_match($pattern, $val)) {
    $suspect = true; //this changes the local variable, not the global one of the same name so ...
    return $suspect;
    }
    }
    }
     
    //if we call the function, we have to supply it with variables
    
    if(isSuspect(anArrayVariable, aRegEx, aBooleanVariable)) {
    //whatever
    }
    
    PHP:
    The problem here is that you're being taught PHP (and an outdated version of it, which you can no longer use) before you've been taught programming. Even if you were being taught the current version, you're being taught a tool (a language) without being taught what it's used for (programming). Learning "saw" is nice, but do you use it for hammering in screws or screwing in nails? That's how you're being taught.

    As an aside, this is a recursive function, which you almost definitely haven't been taught, so you have no idea how it unwinds itself. I'd find a better school or a better instructor. If I had taught programming this way I'd have been a carpenter most of my life, because I would have been fired on the first day.
     
    Last edited by a moderator: Jan 20, 2013
    Rukbat, Jan 20, 2013 IP
    EricBruggema likes this.
  4. knightlightning55

    knightlightning55 Peon

    Messages:
    3
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    1
    #4
    Rukbat,
    Thank you for your answer.
    Its funny because the first thing I thought when I awoke this morning was: 'Maybe I should take a programming class like c++.' My only concern being that it might be a little over my head.
    In regards to your answer, I realize this is a recursive function in that &$suspect causes the value of $suspect to be 'linked' or 'scoped' to outside the function.
    But it is really $val that is giving me a problem and most directly how it gets its value. For instance you remarked:

    1. $val, $pattern and $suspect are local variables
    2. they exist only within this function and have nothing to do
    3. with any variables of the same name that are declared outside this function
    4. */
    5. //this is where you'd declare
    6. global $val, $pattern, $suspect;

    Even if we were to declare our variables in this way, it only causes them to exist, but still does not say to it; "You will hold the information that is in the $_POST array." This is the part that is confusing me.
    When we get to the if statement:
    if (is_array($val)) {
    It is clear the code expects a value to be inside of $val.
    How is that value obtained and where is it coming from?
    You may have answered part of the question already in your note:


    1. //if we call the function, we have to supply it with variables
    2. if(isSuspect(anArrayVariable, aRegEx, aBooleanVariable)) {
    3. //whatever
    4. }

    Does this mean that isSuspect() EXPECTS these types IN THIS ORDER?
    if (isSuspect(anArrayonlyInThisSlot, aRegularExpressionOnlyInThisSlot, onlyABoolHere)
    I appreciate your answer and time.
    Thank you,
    Pete
     
    knightlightning55, Jan 20, 2013 IP
  5. Rukbat

    Rukbat Well-Known Member

    Messages:
    2,908
    Likes Received:
    37
    Best Answers:
    51
    Trophy Points:
    125
    #5
    NO!!! Absolutely not. A C++ class is a language class. You want a programming class. Programming, like almost every other subject, is taught in English. You don't learn plumbing in Plumbing Language, do you? Learn programming in a programming class, then languages will be anywhere from totally trivial (like PHP) to "I have to actually think about this" (like Java and C#). If you understand programming, wear a stiff collar when you take a C++ class - you'll spend most of your time in class nodding. Not nodding off, I hope, but nodding.

    It used to be, and it still is in some languages, but in PHP it's just an esoteric way to throw an error.

    The function definition

    function isSuspect($val, $pattern, $suspect)

    says:

    I am a function named isSuspect. I expect an array variable, a regular expression and a Boolean value, in that order - nothing less and nothing more. (PHP isn't a typed language, so any variable can be any type. So you have to figure out the type of data the variable should hold by context. What the declaration is actually saying is that the function requires 3 variables. Looking at how they're used [like is_array($val)] tells you what type they are.)

    These are basic programming things that you learn in a programming class pretty early - and if you're lucky you learn them quite late in a language class that's being used to teach programming. In a language class in which programming is a prerequisite - which is how a programming language should be taught - it's assumed that you know what a function is, what scope is (local, global, etc.), how a variable gets a value - in a function, outside a function, etc. (BTW, $_POST is just a plain old array and $_POST['x'] is just a plain old scalar or array - you can use them as-is, you don't need to stuff another variable with their value just to use them on the right side [x=y - y is 'on the right side'].)
     
    Rukbat, Jan 20, 2013 IP
  6. knightlightning55

    knightlightning55 Peon

    Messages:
    3
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    1
    #6
    Rukbat,
    I want you to know that I appreciate your help and your time in replying.
    The thing is I already understand a lot of what you are explaining.
    What I am having trouble with is
    :
    How and where from does $val get its value in the code example below?

    Even if isSuspect() is aware that $val must be an array, being in the first position, we still do not see how that array has any information in it. Whether or not &_POST can be written directly is not the question. In the code block below it is not. Okay, fine.
    But how does $val 'connect' to its value?

    Below this code is another (maybe better) example.


    <?php
    // assume nothing is suspect
    $suspect = false;
    // create a pattern to locate suspect phrases
    $pattern = '/Content-Type:|Bcc:|Cc:/i';

    // function to check for suspect phrases
    function isSuspect($val, $pattern, &$suspect) {
    // if the variable is an array, loop through each element
    // and pass it recursively back to the same function
    if (is_array($val)) {
    foreach ($val as $item) {
    isSuspect($item, $pattern, $suspect);
    }
    } else {
    // if one of the suspect phrases is found, set Boolean to true
    if (preg_match($pattern, $val)) {
    $suspect = true;
    }
    }
    }
    Let me provide another example that might help make my question more clear.
    As you can see this is a class. But my question does not pertain to classes. But rather how varibles are passed to functions (in this case methods) without being explicitly set.




    <?php
    class Ps2_Upload {
    //Right away we set our properties to values (and indirectly to their Types, although we know in a //weakly typed language the type can change as the value does.)
    //We know from the below code that the variable named $max exists and holds the value of 51200.

    protected $_uploaded = array();
    protected $_destination;
    protected $_max = 51200;
    protected $_messages = array();
    protected $_permitted = array('image/gif',
    'image/jpeg',
    'image/pjpeg',
    'image/png');
    protected $_renamed = false;
    //When we come to the construct (and again the question does not pertain to constructs) we see $path //passed to the construct.
    //Now this is the problem I am having. We never SET $path to a specific value. We then ask:
    // if $path is not a directory or if $path is not writable, Do this.
    // But...How is $path not just an empty variable?

    Again I want to thank you for your time.
    Sincerely,
    Pete

    public function __construct($path) {
    if (!is_dir($path) || !is_writable($path)) {
    throw new Exception("$path must be a valid, writable directory.");
    }
    $this->_destination = $path;
    $this->_uploaded = $_FILES;
    }

    public function move() {
    $field = current($this->_uploaded);
    $OK = $this->checkError($field['name'], $field['error']);
    if ($OK) {
    $sizeOK = $this->checkSize($field['name'], $field['size']);
    $typeOK = $this->checkType($field['name'], $field['type']);
    if ($sizeOK && $typeOK) {
    $success = move_uploaded_file($field['tmp_name'], $this->_destination . $field['name']);
    if ($success) {
    $this->_messages[] = $field['name'] . ' uploaded successfully';
    } else {
    $this->_messages[] = 'Could not upload ' . $field['name'];
    }
    }
    }
    }
     
    knightlightning55, Jan 20, 2013 IP
  7. Rukbat

    Rukbat Well-Known Member

    Messages:
    2,908
    Likes Received:
    37
    Best Answers:
    51
    Trophy Points:
    125
    #7
    In the code you showed, it doesn't, since nothing calls isSuspect. It's the call of the function that has the value. Where the call gets the value is another matter. Maybe it's a constant, maybe it's passed in the $_POST array, it depends on the particular code. In the example, we don't have that part of the code.

    They can't. The call to the function has the values in the call itself. That's what sets them inside the function. If you're asking how that happens - how the value in isSuspect($item) puts the value into $val on the next call, that's part of the PHP interpreter itself - the values sent to the function (regardless of the names of the variables used) become the values in the variables defined in the function definition. The people who write the PHP interpreter worry about that, the people who write programs in PHP don't - it just magically happens. (Programmers actually talk like that - "it's part of the magic".)

    When we call __construct(), we call it with a value for $path - __construct('/this/path/'); or __construct($myPath); (where we've previously set $myPath to some string representing a path) or __construct($_POST['path']);.
     
    Rukbat, Jan 21, 2013 IP