PHP really scary

I have been trying to learn PHP but I’m not a newbie to programming as I’ve known python language for many years. However here are some constructs that have baffled me:

preg_match(“/abc/”, $str)

PHP seems to require delimiters on each side of the pattern to be matched. So is $str == “abc” then preg_match returns true. However it also returns true if $str = “/abc/” ! Huh??

Also I have run into some string functions that return an index of a substring in a larger string. However its a zero based index so you have a different equality operator === to test for errors. That I find bizarre but I kind of was aware of that so that didn’t shock me too much. However, to my utter petrification I discovered that “strpos(PHP_OS, “WINNT”) !== false” and " strpos(PHP_OS, “WINNT”) === true" return different results!! About this stage the paramedics arrive to restart my cardiovascular system but I am left wondering why??? Is there an answer that someone can give me that will make the above make good sense and restore a sense of calm to what appears to be some very scary PHP constructs? Or is really a huge trap for beginners and a huge obstacle to someone wanting to learn the right way to write software? Or is there a better way to write the above statements that conforms to some best practice for PHP?

I eagerly await your thoughts.

Well it looks to me that the problem you are having is regular expression, not PHP. Regular expression is definitely a pain to learn, in fact I can only understand the most basic syntax of regular expression myself after years of development with PHP softwares. You will likely encounter problems with regular expression even if you use Python or Ruby, this kind of issues are not native to PHP itself.


$result = strpos(PHP_OS, "WINNT") ;  // returns 0 

if($result == false){
        echo 'Win found';
}

// above, because PHP using == smartly compares 0 to false and finds it to be true

if($result === false){
        echo 'Win found';
}

// above, because PHP using === strictly compares 0 to false and finds that to be false

You need to be aware of the PHP truth tables and look closely at the order in which PHP typecasts the elements you want to compare.

If in doubt, always always var_dump() your variables to check not only what value PHP has deemed your variable to be, but what type too.

In your case:


if (PHP_OS === "WINNT"){
// 
}

Would be sufficient.

Ok, I disagree with this. I ran some tests in python to prove it. Here is my code.


>>> print re.match("abc", "abc")
<_sre.SRE_Match object at 0x02970330>
>>> print re.match("abc", "/abc")
None
>>> print re.match("abc", "abc/")
<_sre.SRE_Match object at 0x02970330>

The first argument of re.match() is the pattern and admittedly, in python,
the pattern does not need (and indeed must not have) delimiters around it. Python differs from both PHP
and Perl in this respect. As I said earlier I may be a newbie with PHP but I have
used Python for several years and written major web applications with it. I have
not had any surprises with regular expressions when it comes to python.

Ok, I had a look at the PHP truth tables but it only gave me the truth tables for === and == and not !== nor != which is where I am finding bizarre behaviour. I give you some PHP code to illustrate my point.

Ok, thinking about it I can do this in python with the following:


>>> 'c' in 'abc'
True
>>> 'de' in 'abc'
False

Therefore using the ‘strpos’ function to test for text inclusion might be a bad idea but it was cited as the correct answer on Google search.

With regard to the === and !== operators …

    <p><h3>Equality === Test</h3><?php 
       echo 'PHP_OS = ' . PHP_OS;
       echo '<br/>' . PHP_EOL;
    ?></p>
    <p><?php 
       echo '(strpos(PHP_OS, "WINNT") === true) = ' . (strpos(PHP_OS, "WINNT") === true);
       echo '<br/>' . PHP_EOL;
    ?></p>
    <p><?php 
       echo '(strpos(PHP_OS, "WINNT") !== false) = ' . (strpos(PHP_OS, "WINNT") !== false);
       echo '<br/>' . PHP_EOL;
    ?></p>

And this produces:

PHP_OS = WINNT
(strpos(PHP_OS, "WINNT") === true) = 
(strpos(PHP_OS, "WINNT") !== false) = 1

Hence according to PHP true !== (not false) and therefore, by implication, true === false !!!

OK, I think I finally figured it out. It is possible for both “$x !== false” and “$x !== true” because its only true if $x is of a boolean type so its the python equivalent of:

type(x) == types.BooleanType and x != False

and the equivalent in python would throw an exception:

>>> string.index("cat", "dog")

Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    string.index("cat", "dog")
  File "C:\\Python27\\lib\\string.py", line 328, in index
    return s.index(*args)
ValueError: substring not found
>>> string.index("caravan", "car")
0

so coming from a python background I wasn’t used to jumping through so many hoops.

>>> print re.match(“abc”, “/abc”)
None

Except… that should have matched, because “abc” is contained within “/abc”, no?

From your tests, it looks like Python is inserting a ^ at the start of your pattern (to match the Start of String) without you knowing.


echo preg_match('~abc~',"/abc");
//Returns 1, because the pattern was found in the string.

as far as [FPHP]strpos[/FPHP], if you read the manual it quite clearly states that strpos returns an INT if successful, and a BOOL false if not found. So you would simply check for type.
if(is_int(strpos(…)))
(Or you can check for === false for the negative result)

re.match() will only return a [url=http://docs.python.org/2/library/re.html#re.MatchObject]re.MatchObject only if there is a match from the start of the string. [url=http://docs.python.org/2/library/re.html#re.search]re.search() behaves like our familiar [url=http://php.net/preg_match]preg_match().

So, yes, the former is like adding an starting anchor to the regex.

Yeah I was confused by the method labelling there. Good to know preg_match does a non-anchored search.

My other point was that php requires pattern delimiters (as does Perl) but unlike Perl also matches the delimiter in the string even when I don’t want it to. So in Perl if $x = “/abc” then $x !~ “/abc/” (at least if memory serves coreectly as I’m a bit rusty in Perl) but certainly it is in python where re.search(“abc”,“/abc”) would correctly return false. The whole truth value is opposite in php for preg_match (“/abc/”,“/abc”).

To search for “abc” in python variable it would be:

re.search(“abc”,x)

To get the same effect in PHP you have to:

((strpos($str, “/”) === false ) && preg_match(“/abc/”, $str)

PHP is more cumbersome in this case and more so than other languages.

Well, PHP’s implementation of Regular expressions is [FPHP]PCRE[/FPHP].

My other point was that php requires pattern delimiters (as does Perl)

No points for guessing what the “P” in PCRE stands for :wink:

but unlike Perl also matches the delimiter in the string even when I don’t want it to. So in Perl if $x = “/abc” then $x !~ “/abc/” (at least if memory serves coreectly as I’m a bit rusty in Perl) but certainly it is in python where re.search(“abc”,“/abc”) would correctly return false. The whole truth value is opposite in php for preg_match (“/abc/”,“/abc”).
Uh… no? re.search should return true, because the pattern (abc) is in the haystack (/abc)? Also PHP does NOT use the delimiter in it’s pattern. I’d like to see what code you’re using that indicates otherwise.


preg_match('/abc/','/abc',$matches);
print_r($matches);
//Output: Array ( [0] => abc ). Note the lack of delimiter in result.

More simply, To find the string “abc” in “/abc” in PHP: strpos(“/abc”,“abc”). (This of course is a simplified case because the patterns are simple strings, and thus dont actually need the power of Regular Expressions.)

EDIT: strpos is haystack,needle and not needle, haystack.

Oh, Starlion, looks like you’re right. Just goes to show I have been using re.match() all this time subconsciously thinking the same semantics apply to preg_match when its closer to re.search() which I haven’t used much, even in python. I modified the patterns to use “/^abc$/” and they now work.

It seems my problems in learning PHP have come mostly from thinking in python.