Differences between PHP Arrays and Ruby Hashes
We've looked at the diferences between Ruby and PHP arrays before. Now lets compare PHP arrays and Ruby hashes. They should be similar as all PHP arrays are implemented as hashes. There is however a cruicial difference that can trip you up if you are switching from one language to another.
Referencing an index that hasn't been set is an error in PHP, but not in Ruby.
In PHP, retreiving a value for an index that you haven't used is a warning. Although warnings can be turned off it is best practice to develop with them turned on.
<?php
$a['key1'] = 'value1';
$a['key2'] = 'value2';
print $a['key5'];
/*
lang@virtualbox1:~/$ php hash.php
PHP Notice: Undefined index: key5 in /home/lang/hash.php on line 6
*/
?>
In Ruby you can set a default value for all keys that have not set a value. By default this value is nil.
a = Hash.new
a['key1'] = 'value1'
a['key2'] = 'value2'
puts a['key5']
=begin
lang@virtualbox1:~/$ ruby hash.rb
nil
=end
Ruby hashes are unordered (up to version 1.8). PHP arrays have an internal order seperate from their index.
When you loop through a PHP array, the values will be returned in the order they were added.
<?php
$a['key1'] = 'one';
$a['key0'] = 'zero';
foreach($a as $value) {
print $value . "\n";
}
/*
lang@virtualbox1:~/$ php hash.php
one
zero
*/
?>In Ruby 1.8 hashes are unordered, they could be retreived in any order that ruby decides is best. Ruby 1.9 changes this so that it works in the same way as the PHP example above.
a = Hash.new
a['key1'] = 'one'
a['key0'] = 'zero'
a.each_value do |value|
puts value
end
=begin
lang@virtualbox1:~/$ ruby hash.rb
zero
one
=end
Is there anything that has been missed? Add a comment below.
Major differences between PHP and Ruby Arrays
PHP has a single array type, where as Ruby has Array and Hash, which covers the same functionality. In this article i'll go though the three major logical differences between PHPs array type and Rubys Array classs. We compare PHP arrays and Ruby Hashes in seperate post.
Firstly,
PHP arrays have an internal order seperate from their index.
Lets look at a simple example. In php the order you insert values into an array
determines the order that php will return them using foreach
<?php
$a[1] = 'one';
$a[0] = 'zero';
foreach($a as $value) {
print $value . "\n";
}
/*
lang@virtualbox1:~/arrays$ php array.php
one
zero
*/
?>Ruby on the other hand uses the key or index of the array to determine the order, regardless of order in which the values are inserted.
a = Array.new
a[1] = 'one'
a[0] = 'zero'
a.each do |value|
puts value
end
=begin
lang@virtualbox1:~/arrays$ ruby array.rb
zero
one
=endSecondly,
Ruby arrays always start at 0 and end at the highest index. PHP arrays only contain the keys that have been entered.
In the example below, PHP will output the two array values that are set.
<?php
$a[2] = 'two';
$a[4] = 'four';
foreach($a as $value) {
print $value . "\n";
}
/*
lang@virtualbox1:~/arrays$ php array.php
two
four
*/
?>In the ruby example, not only are the two values output, but an attempt is made to get the value from every index between 0 and the highest index set.
a = Array.new
a[2] = 'two'
a[4] = 'four'
a.each do |value|
puts value
end
=begin
lang@virtualbox1:~/arrays$ ruby array.rb
nil
nil
two
nil
four
=endThis leads to another difference…
Referencing an array index that hasn't been set is an error in PHP, but not in Ruby.
The following code produces a PHP notice. Notices are a low severity error, and are usually turned off on production servers. However it is considered good practice to develop with notices turned on.
<?php
$a[2] = 'two';
$a[4] = 'four';
print $a[5];
/*
lang@virtualbox1:~/arrays$ php array.php
PHP Notice: Undefined offset: 5 in /home/lang/arrays/array.php on line 6
*/
?>Ruby on the other hand does not consider this an error. It will return the nil value which is 'kind of' like PHPs null.
a = Array.new
a[2] = 'two'
a[4] = 'four'
puts a[5]
=begin
lang@virtualbox1:~/arrays$ ruby array3.rb
nil
=end
So what are your experiences switching between PHP and Ruby. Let me know in the comments below.
Speak the truth 1
Improper uses of Booleans causes headaches for people who are reviewing your code. Lets take a look at some good, and not so good uses.
Don't be negative
if $notLoggedIn then
Looks simple and readable right? Wrong. It's one step away from being misused.
if ! $notLoggedin then
Not not logged in. Double negatives are a gotcha in language and coding and should be avoided. Fortunately the solution is an easy one. Remove the negative prefix (such as not, doNot, dont) from the variable name.
if $loggedIn then if ! $loggedIn then
Hide Literals
if $hidden == false then
Is it really necessary to compare the variable to false?
Imagine this conversation. You are at Subway and they ask you
"Would you like your sandwich toasted?"
Would you reply with
"Toasted equals false"
Or
"Not Toasted"
Avoid comparing with a literal true or false. The correct way to express this is :-
if ! $hidden then
A Boolean Flag?
if $reportFlag then
$reportFlag is a little vague. In this case it is determining if an object is included in a report. So if $reportFlag is true, does that mean that the object is included or excluded? If you have to ask yourself the question then you have already failed and need to rethink what this variable should be called.
if $report then
This is okay as long we are using the word 'report' as a verb. "If we report this then" is how you would read this. Some people may not be able to make that leap so if you want to be more precise you could make it :-
if $includeInReport then
Summary
So to sum up, these three things will go a long way to making your code readable.
- Remove the negative prefix (such as not, doNot, dont) from variable names.
- Avoid comparing with a literal true or false.
- Avoid vague terms like flag for Boolean values.
Consider these ideas when choosing
- Variable names
- Object properties
- Database field names
- Method or function parameter names
Anything Else?
Is there something i've missed? A hole you could drive a double-decker bus through? Leave a comment below.
WTF - Scheduled Reports
Working on scheduled reporting systems, you expect to see the same concepts. What format wiil we send the report in? How will it be delivered? I opened the “scheduled report” table to see how this particular system had been implemented. I couldn’t immediately find which column i was looking for. In fact the only one that looked like it might be useful was something called deliv_method.
deliv_method
206
774
206
206
Ok, so we’ve got a numeric list of delivery methods. Nothing too unusual about that. I just need to find the list either in the database or codebase. But where do we store the format of the report? I worked my way through the report scheduler code until i found this.
$delivMeth = ($row[‘DELIV_METHOD’] >> 8);
$myFormat = ($row[‘DELIV_METHOD’] & 0xFF);
Are those bitwise operators? And even a literal hexadecimal number? The only place i’ve ever seen a bitwise operator is when setting the error reporting level. I’ve looked at this a few times and am still not sure i correctly understand it.
The answer eventually revealed itself.
$a = array(
0x0104 => "Email HTML",
0x0204 => "Email HTML Attachment",
0x0284 => "Email HTML Zipped attach",
0x0201 => "Email PDF",
0x0203 => "Email TSV delim",
0x0283 => "Email TSV delim zipped",
0x0203 => "Email CSV delim",
0x0283 => "Email CSV delim zipped",
0x0304 => "FTP HTML",
0x0301 => "FTP PDF",
0x0303 => "FTP TSV delim",
0x0303 => "FTP CSV delim",
);
Pretty clever you have to admit! Unfortunately it can lead to same rather ugly code.
if ((($('#INPUT\[DELIVERY_METHOD\]').val() & 0xFF00) >> 8) != 0x03){
Glue code
Glue is what holds your application together. Code needs to talk to databases, Javascript is calling your PHP functions using Ajax. When two systems, or different parts of the same system need to talk to each other, you end up with glue. It (hopefully) doesn't have any business logic. It's used or copied by at least a few different parts of your system, perhaps even in different projects in the same organisation.
Glue code holds things together. The only problem is that glue is not your application. Unless you're developing a framework, operating system or perhaps something that needs plugins, glue is not your strength. There are always exceptions but if you are writing glue, especially the same glue for the 3rd or 4th time, then you're not directly working on the application you are building.
Having said that, your project won't survive without glue. So how do you keep everything together?
- Recognise glue. The first step is to understand that you are now writing glue code and not working on business requirements. For example, say you are writing a script to process files that are uploaded to your server. Discovering the files is glue, the processing of then is specific to your application.
- Standardise across your organisation. Glue may start out as a one off but as time moves on it will become apparent which pieces are worth time improving and which aren't.
- Make it as simple to use as possible. It will need to be understood by a larger group of developers than your other code. Put that extra time into documentation and code beautification.
- Make it as robust as possible. You don't want this getting in the way of your 'actual' work.
- Use 3rd party glue. Someone has nearly always been before you. Wiring your PHP and JS together with AJAX? It's been done. Creating a DB access class? Been there, done that. If you think you can do better your probably wrong. You may write better code, but you probably won't document or test it as thoroughly as an open source project has already been.
In conclusion, you want to keep glue simple and straight forward. Recognise what is and isn't glue in your application. Share the glue you have with every one in your team, and if your brave, the outside world.
The idea of glue is described in Eric Raymond's excellent book The art of unix programming.