Friday, September 30, 2011

Zend Studio Potential Programmer Problems settings For Refactoring

Zend Studio is the best PHP IDE i've ever seen so far. It can warn us for some 'Potential Programmer Problems'. For example, it can warn us if we are using some undefined local variables in our code.  This feature is so valuable when we are refactoring large, long procedure legacy code to smaller functions and OO code. One of the worst coding practice is the large and heavy dependency on global variables. One purpose of refactoring is to break the dependency, so we must be very careful to find out all the dependency and pass them as parameters. Without IDE's help, it is hard for developer himself to find out these dependency from a mess of large long procedure code.

But i find one issue that Zend Studio would not warm me, and it is also very common in code: if we are using a field/property of an undefined object, Zend Studio would not warn us! Check this procedure code example, assuming all the variables/objects/functions are in another file:

echo $name;
echo $information->getEmail();
echo $car->brand;

We have three dependency here, $name, $information, $car. If we want to change the procedure code into a function:

function render()
{
echo $name;
echo $information->getEmail();
echo $car->brand;
}

After we create the function, we ask Zend Studio to check for any Potential Programmer Problems, but Zend Studio would only warn us for 'undefined variable $name' and 'undefined variable $information'. It would not give any warning even $car is also an undefined variable. So to remove the warning, we change our function to

function render($name, $information)
{
echo $name;
echo $information->getEmail();
echo $car->brand;
}

Now we think everything is fine, but actually we still miss one dependency! I've been through this a few times and I feel it is ridiculous that Zend Studio ignores undefined object field. So i check Zend Studios Potential Programmer Problems settings and find this: Undefined field(slow check) : Ignore(default). If i change it to Warning, and ask Zend Studio to check again, this time it can give me a warning for undefined $car->brand as well. However, it is far from perfect yet, cause Zend Studio would give warning for every accessing to object properties, even the properties are really defined in the object.

I think this lesson also tells us one thing: directly accessing an object's fields without using getter methods probably is not a good idea, although this really depends.

Friday, September 23, 2011

php get domain name from url

Regular Expression probably will be the first idea coming up in your mind. But it turns out the task could be much easier in PHP:

$domain = parse_url($url, PHP_URL_HOST);

Friday, September 2, 2011

Memcached::WRITE FAILURE

This issue bothers me today. My environment is ubuntu 10.10 + PHP5.3. Both memcached and php5-memcached are installed correctly, and memcached service is running properly.

Here is my testing code, copied from PHP manual:

//first part, testing Memcache
$memcache_obj = new Memcache;$memcache_obj->connect('localhost'11211);
$memcache_obj->set('var_key''some really big variable'MEMCACHE_COMPRESSED5000);
echo 
$memcache_obj->get('var_key');



//second part, testing Memcached
$m = new Memcached();$m->addServer('localhost'11211);
$m->set('int'99);$m->set('string''a simple string');$m->set('array', array(1112));


var_dump($m->get('int'));var_dump($m->get('string'));var_dump($m->get('array'));


The result is quite confusing me: the first part, testing Memcache, works very well. But the second part, testing Memcached doesn't work! Instead, the result message is WRITE FAILURE, the result code is Memcached::RES_WRITE_FAILURE.

As usual, the message doesn't help much in debugging. I google this issue, but cannot find any helpful solution. I even removed memcached(I installed them using sudo apt-get install) and then download the packages and install them manually(./configure, make, make install). But still cannot solve the problem. And i almost think probably it is a ubuntu bug and i have to upgrade my ubuntu(PHP manual explains Memcached::RES_WRITE_FAILURE means 'Failed to write network data').

At last, i just 'accidently' change Memcached 'localhost' to 127.0.0.1, and it turns out that this accident solves the problem! But what i still get confused with is why Memcahe can use 'localhost' while Memcached have to use '127.0.0.1'. Shouldn't be either they both must use 'localhost' or they both have to use '127.0.0.1'?

pecl/pear proxy settings


set proxy:
sudo pecl config-set http_proxy xxxx http://username:password@yourproxy:80

unset proxy:
sudo pear config-set http_proxy “”

Wednesday, August 31, 2011

jQuery check if dom element exists

When we use jQuery method $("#idName"), we will always get a jQuery object, even the DOM element may not be really existing on the web page. Sometimes we want to check if the returned object by $("#idName") really is an existing DOM element on the page. The easiest way to do this is to check the length property of the object:

var fakeDom = $("#fake");
if (fakeDom.length == 0) {
console.log('i am not an existing DOM);
}

There is another way to do this though:

var fakeDom = $("#fake");
if (fakeDom[0] === undefined) {
console.log('i am not an existing DOM);
}

Why do they work? When we check jQuery source code (v1.6.2), we find this:

// HANDLE: $("#id")
else {
elem = document.getElementById( match[2] );

// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}

// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}

this.context = document;
this.selector = selector;
return this;
}

As we can see, jQuery gets the DOM element: elem = document.getElementById( match[2] ). And if the DOM element is valid, it will set the length property of jQuery object to 1:

elem = document.getElementById( match[2] );
if ( elem && elem.parentNode ) {
...
this.length = 1;
this[0] = elem;
}
...
return this;

So, if elem is not a valid DOM, this.length will be 0. From the source code, we also find that the valid DOM elem will be assigned to this[0]. Therefore, if the elem is not valid DOM, this[0] should be undefined. So we can also check if this[0] is undefined.  

Thursday, August 25, 2011

Explicit is better than implicit

Explicit is better than implicit is one of python's Zen. Coming to PHP, however, there are too many ways to make things implicitly. One of them is variable variable:


$var = 'name';
$$var = 'henry';
echo $name;

The output is 'henry'. Maybe this code snippet is not that horrible. But sometimes it is not that simple.

There was once I tried to locate where a variable is defined. The variable is $branchName, for example. It is being used directly in a file in this way: echo $branchName; and it works, so the variable must be defined/assigned a value somewhere else. Since the legacy code is procedure style, so I naturally trace back to other files that are included into the file. It must be one of those included files in which $branchName is defined. However, I can't find it. So i start to search the whole application, but i still can't find any place that defines $branchName.

The first possibility i can come up with is, register global, another notorious php feature. The application is so old that register global is turned on and used. Unfortunately, I still can't find any place showing that $branchName is a register global.

Then, i think that must be a variable variable, so i search the string '$$' in those included files. I cannot find any. I start to get a little confused. But suddenly, i remember that PHP can define variable variable in two ways: $$var = 'henry' or ${$var} = 'henry'. They both work. So i try to search '${$' in the files, finally, i found this code, with a comment from a prior developer, which is funny:


for ($i = 0, $last = count($parameters); $i < $last; $i++) {
        //Good ol' dollar-dollar string interpolation... um, yeah, "thanks".
    ${$parameters[$i]['name']} = $parameters[$i]['value'];
}

When i var_dump($parameters), I finally found this 'branchName'. PHP can make things so implicitly, and even worse, it provides different ways to do implicit thing while Python preaches there should be only one way to do the same thing. That is why when i learned the fact that "Ruby inherited the Perl philosophy of having more than one way to do the same thing", I immediately dump this language into my rubbish bin and never want to touch it again, unless i was forced to.

Wednesday, August 24, 2011

shift array elements to the right in PHP

Another algorithm related question for C/C++ devs. It is always interesting to see how to solve it in PHP.

The question is: implement a function to shift $k array elements to the right. Time complexity must <= O(n)
For example, we have an array $a = array('a', 'b', 'c', 'd', 'e'), a function rightShift($array, $k), and if we call rightShift($a, 2), the return result must be array('c', 'd', 'e', 'a', 'b'). 'a' and 'b' have been shifted to the right of the array.

It is quite simple in PHP, with PHP's array functions.

function rightShift($array, $k)
{
                for($i=0; $i<$k; $i++) {
                                $temp = array_shift($array);
                                array_push($array, $temp);
                }
                return $array;
}

Even without using PHP array function, it is still simple:

function rightShift($array, $k)
{
                for($i=0; $i<$k; $i++) {
                                $temp = $array[$i];
                                unset($array[$i]);
                                $array[] = $temp;
                }
                return $array;
}

The function works and the complexity is O(n), so it meets the requirement.

But there is a flaw with the rightShift function and that is always easy for people to neglect. We don't carefully consider the value of $k. If $k <= 0, that is fine, the array keeps same. But what if $k > count($array)? We tend to assume $k < count($array) so in the function we don't do anything about it. Actually, $k could be much bigger than count($array). The function still works when $k > count($array), but obviously, it is not efficient.

So let's consider when $k > count($array). In this example, if $k = 8, what the result should be? It should be array('d', 'e', 'a', 'b', 'c'). We can find that we don't really need to shift $k times, we only need to shift $k % count($array) times. So, let's change our code:

function rightShift($array, $k)
{
                $k = $k % count($array);
                for($i=0; $i<$k; $i++) {
                                $temp = $array[$i];
                                unset($array[$i]);
                                $array[] = $temp;
                }
                return $array;
}

This will actually introduce another issue: what if count($array) === 0? So, we need to check this:

function rightShift($array, $k)
{
                $total = count($array);
                if ($total === 0) {
                                return false;
      }
                $k = $k % $total;
                for($i=0; $i<$k; $i++) {
                                $temp = $array[$i];
                                unset($array[$i]);
                                $array[] = $temp;
                }
                return $array;
}