Skip to content
Jun 4 / John Wyles

Just Bought the HTC EVO 4G

The Sprint HTC EVO 4G is now mine to have and hold and there is a lot to have and to hold. It is the widest and longest phone I have handled in the past 8 years. It also is, hands down, the sexiest UI on the market (iPhone included) and makes brilliant use of the Sense UI.

Photos source: Gizmodo

May 30 / John Wyles

MongoDB Rails Skeleton

I have a more than a few rails application skeletons now that make use of MongoDB and have various other common components so I thought it would be worthwhile to summarize them with a rails skeleton. The skeleton can be found on github under johnwyles/skeleton. The skeleton includes the following:

  • Persistence
  • Authentication and Authorization
    • Devise
    • CanCan
    • AASM (overwritten by: johnwyles/aasm)
    • AASM::StatefulResource (included in: lib/aasm/stateful_resource.rb)
  • Display
    • HAML
    • Compass
    • Formtastic
    • will_paginate
  • Testing
    • Cucumber
    • Capybara
    • Culerity
    • rSpec
    • factory_girl
    • database_cleaner
  • Configuration
    • AppConfig (included in: config/initializers/00_appconfig.rb)
    • i18n (included in: config/initializers/01_locales.rb)

AppConfig is a short little initializer with OpenStruct that reads a YAML file and loads various application specific settings (e.g. Application Name, Session Secret, Domain, etc.).

May 4 / John Wyles

kog: A Ruby implementation of The Open Graph Protocol by Facebook

As I am sure many of you have heard Facebook announced their schema to assist with building the semantic web: The Open Graph Protocol. And while Facebook clearly acknowledges they have not done anything particularly new or innovative with it, I think for many simply hearing the concepts and techniques spoken again by a social networking giant signaled the timing is right and we should start to see some real results this time around. So, with all that energy, I drew up my version of the protocol as a ruby implementation to further reinforce and validate my interests in Ruby (again). I’ve been sitting on this code a little while expecting to divine more features for it. However, rather than sitting on it any longer waiting around for the code rot, I thought it best to simply unleash it upon the world complete with rSpec coverage and a single Cucumber feature: Kestrel Open Graph (kog).

To install simply perform:

# Installation of kog
sudo gem install kog

Using kog is very simple as illustrated below:

require 'rubygems'
require 'kog'

# Parse a resource and getting the resource
obj = OpenGraph::Parser.parse('http://www.rottentomatoes.com/m/office_space/')
puts obj.class # => OpenGraph::Object

# The object
puts obj.inspect # => #<OpenGraph::Object:0x101b01060 @image="http://images.rottentomatoes.com/images/movie/custom/aa/1087856aa.jpg", @title="Office Space", @url="http://www.rottentomatoes.com/m/office_space/", @site_name="Rotten Tomatoes", @type="movie">

# Accessors
puts obj.type # => movie
puts obj.type?('movie').inspect # => true
puts obj.type?('dog').inspect # => false

That’s it! Now wasn’t that easy?

Apr 27 / John Wyles

Creating a Shared Git Repository For Multiple Users

It took mashing together multiple articles, blog posts, and wikis to put this all together but I finally have a process for hosting a “centralized” shared git repository that honors file permissions for the respective users. The way in which you do this is the following:

On the server:

# Create a git repository
sudo mkdir -p /var/git
cd /var/git
sudo mkdir myproject
pushd myproject
sudo git init
sudo touch .gitignore
sudo git add .gitignore
sudo git commit -a -m 'Initial import'
popd

# Clone the bare git components away
sudo git clone --bare myproject myproject.git
pushd myproject.git

# Set the type of shared repository this will be
sudo git config core.sharedRepository group
popd

# Change the file permissions
sudo chown -R root:users myproject.git # Replace "users" with your group
sudo chmod -R g+ws myproject.git

On the clients:

git clone username@example.com:/var/git/myproject.git

That should be the basics without going a step further and creating a “git” user and group to host the service as. Enjoy!

Apr 24 / John Wyles

Turning a Pickcle into a Cucumber

I had seen Cucumber before but never really had any time to dabble with it and now that I have I cannot put it down! After setting up a skeleton Ruby on Rails application using Cucumber, Capybara, Devise, and FactorGirl (along with Haml, Compass, and MongoMapper) I decided to circle back and write some Cucumber features to cover the basic user interactions: sign up, confirmation, login, logout, lost password, etc. While it took me much longer than I expected my journey was very fruitful; it turns out some of the Features and their subsequent Scenarios were entirely covered by Cucumber and Capybara without me needing to write one bit of “glue code” to make them work (Cucumber calls these “step definitions”). Most of the time I spent was refactoring out step definitions over and over until I found I did not need a single one! Here is the final product from the “Signing Up” feature:

# features/authentication/signup.feature

Feature: Signing Up
  In order to sign up for an account
  As a guest
  I need to be able to register

  Scenario: Registration
    Given I am on the sign up page
    When I fill in "user_email" with "test@example.com"
    And I fill in "user_password" with "test1234"
    And I fill in "user_password_confirmation" with "test1234"
    And I press "Sign Up"
    Then I should see "You will receive an email with instructions"

Even after all of this I cannot be sure that I have completely covered the test but I will note that it does not require a single step definition outside of those that are provided by Capybara in the web_steps.rb convenient step definitions. Here are the other Features, Backgrounds, Scenarios, and Scenario Outlines that I used to cover the authentication class of features:

The confirmation feature:

# features/authentication/confirmation.feature

Feature:
  In order activate my account
  As a user
  I want to be able to confirm

  Background:
    Given I am pending confirmation

  Scenario: Confirmation
    Given I received the email
    When I confirm the account
    Then I should find that I am confirmed

The session feature:

# features/authentication/session.feature

Feature: Session handling
  In order to use the site
  As a registered user
  I need to be able to login and logout

  Background:
    Given that a confirmed user exists

  Scenario Outline: Logging in
    Given I am on the login page
    When I fill in "user_email" with "<email>"
    And I fill in "user_password" with "<password>"
    And I press "Sign in"
    Then I should <action>
    Examples:
      |         email       |  password   |              action             |
      | minimal@example.com |  test1234   | see "Signed in successfully"    |
      | bad@example.com     |  password   | see "Invalid email or password" |

  Scenario: Logging out
    Given I am logged in
    When I go to the sign out link
    Then I should see "Signed out successfully"

The forgotpassword feature:

# features/authentication/forgotpassword.feature

Feature: Forgot password
  In order to login
  As a user
  When I have forgotten my password
  I should be able to reset it

  Background:
    Given that a confirmed user exists

  Scenario Outline: Reset password request
    Given I am on the forgotten password page
    When I fill in "user_email" with "<email>"
    And I press "Send me reset password instructions"
    Then I should <action>
    Examples:
      |         email       |                                       action                                       |
      | minimal@example.com | see "You will receive an email with instructions about how to reset your password" |
      | bad@example.com     | see "Email not found"                                                              |

  Scenario: Reset password confirmation
    Given that I have reset my password
    When I follow the reset password link in my email
    Then I expect to be able to reset my password

and all of the step definitions:

# features/step_definitions/authentication_steps.rb

# Confrimation
Given /^I received the email$/ do
  @user.confirmed?.should be_false
end

When /^I confirm the account$/ do
  visit user_confirmation_path(:confirmation_token => @user.confirmation_token)
  page.should have_content("Your account was successfully confirmed")
  @user.confirm!
end

Then /^I should find that I am confirmed$/ do
  @user.confirmed?.should be_true
end

# Forgottenpassword
Given /^that I have a confirmed account$/ do
  @user.confirmed?
end

Given /^that I have reset my password$/ do
  @user.send_reset_password_instructions
end

When /^I follow the reset password link in my email$/ do
  visit edit_user_password_path(:reset_password_token => @user.reset_password_token)
  page.should have_content("Change your password")
end

Then /^I expect to be able to reset my password$/ do
  visit edit_user_password_path(:reset_password_token => @user.reset_password_token)
  fill_in 'user_password', :with => 'test1234'
  fill_in 'user_password_confirmation', :with => 'test1234'
  click_button('Change my password')
  page.should have_content('Your password was changed successfully')
end

# Session
Given /^I am logged in$/ do
  visit path_to('the login page')
  fill_in('user_email', :with => @user.email)
  fill_in('user_password', :with => @user.password)
  click_button('Sign in')
  if defined?(Spec::Rails::Matchers)
    page.should have_content('Signed in successfully')
  else
    assert page.has_content?('Signed in successfully')
  end
end

To get the minimal user, referenced in a few of the step definitions, I created a Factory:

# spec/factories/user.rb

Factory.define :minimal_user, :class => User do |u|
  u.email 'minimal@example.com'
  u.password 'test1234'
  u.password_confirmation 'test1234'
end

And added the FactoryGirl gem to the Cucumber environment:

# config/environments/cucumber.rb

config.gem "factory_girl"

As you can see there is a lot here and a lot of it probably duplicates the test coverage found in the Devise gem. However, developing these Features, Scenarios, and Step Definitions has been great practice for me and warmed me up very gently to how fun Behavior Driven Design (BDD) can be.

Mar 24 / John Wyles

Fun with Ruby and the Collatz Conjecture

I’ve been growing a little hungry to dive back into Ruby a bit and the opportunity arose after stumbling on reading about the Collatz Conjecture (of which there is a funny xkcd comic) and finding some spare time on a connecting flight. It basically states that for any number, if you continually divide by two, if even, or multiply by three and add 1, if odd, you will eventually get to 1. All of the intermediate numbers are referred to as the path that make up that number; for example, the number 5 has the following path: [16, 8, 4, 2, 1] where the steps are 5 (x 3 + 1) => 16 (/ 2) => 8 (/ 2) => 4 (/ 2) => 2 (/ 2) => 1. I thought I would have a bit of fun with this and build some utility functions around what you might want to know about two number paths in the collatz conjecture. All of this code was written very hastily but it was fun and killed a couple of hours of boredom stuck on a plane. This is the result:

#!/usr/bin/env ruby

class Collatz
  def self.get_convergence_point(number_one, number_two)
    self.get_path_intersection(number_one, number_two).first
  end

  def self.get_path_intersection(number_one, number_two)
    # Get the paths
    path_one = self.get_path(number_one)
    path_two = self.get_path(number_two)

    # Return the intersection
    path_one & path_two
  end 

  def self.get_path_matrix(number, matrix=Hash.new)
    # Get all of the "child" numbers for this number
    numbers = self.get_path(number)

    # Itterate
    numbers.each do |n|
      # Save some work
      if (matrix[n].nil?)
        matrix[n] = self.get_path(n)

        # Done
        if (n == 1)
          return matrix
        end

        # Recursive
        return self.get_path_matrix(n, matrix)
      end
    end
  end

  def self.get_step_count(number)
    self.get_path(number).length - 1
  end

  def self.get_path(n, numbers=Array.new)
    # Append current itteration
    numbers << n

    # Done
    if (n == 1)
      return numbers
    end

    # Recursive
    if(n%2 == 1)
      self.get_path((3*n)+1, numbers)
    else
      self.get_path(n/2, numbers)
    end
  end
end

## Get some info
matrix_one = Collatz::get_path_matrix(ARGV[0].to_i)
matrix_one_step_count = Collatz::get_step_count(ARGV[0].to_i)
matrix_two = Collatz::get_path_matrix(ARGV[1].to_i)
matrix_path_intersection = Collatz::get_path_intersection(ARGV[0].to_i, ARGV[1].to_i)
matrix_convergence_point = Collatz::get_convergence_point(ARGV[0].to_i, ARGV[1].to_i)

puts matrix_one.inspect
puts matrix_one_step_count.inspect
puts matrix_two.inspect
puts matrix_path_intersection.inspect
puts matrix_convergence_point

## Empty space
puts
puts

## Print "pretty" path
path_one = Collatz::get_path(ARGV[0].to_i)
path_two = Collatz::get_path(ARGV[1].to_i)
path_convergence_point = Collatz::get_convergence_point(ARGV[0].to_i, ARGV[1].to_i)
path_intersection = Collatz::get_path_intersection(ARGV[0].to_i, ARGV[1].to_i)

if path_one.length >= path_two.length
  left_path = path_one
  right_path = path_two
else
  left_path = path_two
  right_path = path_one
end

left_path -= matrix_path_intersection
right_path -= matrix_path_intersection
path_intersection.reverse.each do |n|
  if (!right_path.empty?)
    puts '  ' + n.to_s
  else
    puts n.to_s
  end
end

if (!right_path.empty?)
  puts ' / \\'
end

left_path.reverse.each do |x|
  next if (x == path_convergence_point)
  puts x.to_s + "   " + right_path.pop.to_s
end

This yields the output:

$ ruby collatz.rb 7 6
{16=>[16, 8, 4, 2, 1], 5=>[5, 16, 8, 4, 2, 1], 11=>[11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1], 22=>[22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1], 17=>[17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1], 1=>[1], 34=>[34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1], 40=>[40, 20, 10, 5, 16, 8, 4, 2, 1], 7=>[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1], 2=>[2, 1], 13=>[13, 40, 20, 10, 5, 16, 8, 4, 2, 1], 8=>[8, 4, 2, 1], 52=>[52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1], 20=>[20, 10, 5, 16, 8, 4, 2, 1], 4=>[4, 2, 1], 26=>[26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1], 10=>[10, 5, 16, 8, 4, 2, 1]}
16
{16=>[16, 8, 4, 2, 1], 5=>[5, 16, 8, 4, 2, 1], 6=>[6, 3, 10, 5, 16, 8, 4, 2, 1], 1=>[1], 2=>[2, 1], 8=>[8, 4, 2, 1], 3=>[3, 10, 5, 16, 8, 4, 2, 1], 4=>[4, 2, 1], 10=>[10, 5, 16, 8, 4, 2, 1]}
[10, 5, 16, 8, 4, 2, 1]
10

  1
  2
  4
  8
  16
  5
  10
 / \
20   3
40   6
13
26
52
17
34
11
22
7
Mar 16 / John Wyles

Money Sometimes is the Answer or A Hundred Ways to Make a First Impression

I take the train each day into work and frequently encounter someone pedeling their wares or passing out flyers as I exit the terminal on my way in to work. This day being no exception I encounter a female lunging at me with something in her hand while demanding “Here!”. I’d been bothered before to take a flyer or newspaper but never have I had anyone be so in my face about it. Naturally I was turned off of whatever she was offering, until I looked down and saw this:

My initial reaction was that someone or some company just might crazy or stupid enough to hand out a hundred dollar bill with a note attached as some sort of whacky marketing campaign so I obliged her offer and took what she offered. Immediately after I took it into my hand the “too good to be true” thought started to creep in so I inspected the dimensions of what I had just received:

A phony! Hey now, that’s not fair! But they already had me. The “money” was already in my hand and I was walking further away from the peddler. Of course my next reaction was to laugh and ask who was so wickedly clever and I discover another, albeit less surprising, find:

Ahhhhh! It’s tax season! And I haven’t done my taxes yet! You bastards!

Update: One other thing I realized is that the depths of cleverness of using a hundred dollar bill as the cover for your leaflet is that if it is tossed on the ground as trash someone else will likely come along and the process repeat itself. Brilliant!

Mar 15 / John Wyles

Sessions in MongoDB using MongoMapper and Devise

I found that setting up MongoDB to be a session store using MongoMapper was, at first glance, non-obvious: that is, until I discovered devise. At first, I tried (and failed) to setup sessions in authlogic and then moved to the other end of the spectrum and attempted to role my own authentication and session store using this gist as a starting point. While it worked it felt wrong and I foresaw rewriting a ton of features that came for free with most authentication plugins. So, after an even more exhaustive search, I found devise; what a wonderful find! Nothing in devise said it wouldn’t work and I indeed found that to be the case; it was really agnostic to the session store and extremely simple to setup. Since devise is built atop warden.

So lets get started, first off you need to get the required gems and a skeleton app:

sudo gem install ruby-debug mongo mongo_ext mongo_mapper warden devise
rails myapp
cd myapp
rm public/index.html

Setup the environment.rb with some changes we will require:

# config/environment.rb

config.gem 'mongo_mapper'
config.gem 'devise'

Update the route for the home controller:

# config/routes.rb

# devise user definition
map.devise_for :users
map.resource :user, :o nly => [:new, :create, :edit, :update]

# root
map.root :controller => :user, :action => :sign_in

Generate the scaffold for the session and user model:

script/generate devise_install
script/generate devise User

Modify the generated user model:

# app/models/user.rb

class User
  include MongoMapper::Document
  devise :registerable, :authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
end

Sterilize the logs for sensitive information:

# app/controllers/application_controller.rb

filter_parameter_logging :password, :password_confirmation

Remove ActiveRecord from the environment:

# config/envrionment.rb

config.frameworks -= [ :active_record ]

Replace database.yml with the following:

# config/database.yml

development:
  adapter: mongodb
  database: myapp-development
  host: localhost

test:
  adapter: mongodb
  database: myapp-test
  host: localhost

production:
  adapter: mongodb
  database: myapp-production
  host: localhost

Add mongo_mapper YAML initializer:

# config/initializers/mongo_mapper.rb

# load YAML and connect
database_yaml = YAML::load(File.read(RAILS_ROOT + '/config/database.yml'))
if database_yaml[Rails.env] && database_yaml[Rails.env]['adapter'] == 'mongodb'
  mongo_database = database_yaml[Rails.env]
  MongoMapper.connection = Mongo::Connection.new( mongo_database['host'])
  MongoMapper.database =  mongo_database['database']
end

Enable mongo_mapper support for devise:

# config/initializers/devise.rb

Devise.setup do |config|
  config.orm = :mongo_mapper
end

You can now startup the server:

script/server -u

Now point your browser to http://127.0.0.1:3000/users/sign_up and sign up for an account.

Use the mongo client to get out the confirmation code:

mongo
> use myapp-development
> db.users.find();
{ "_id" : ObjectId("4c9e9118af5ee501860230004"), "encrypted_password" : "18cf5678ba4ef9d412c3b7bdea48794b7c69ec3a", "created_at" : "Mon Mar 15 2010 18:44:56 GMT-0700 (PDT)", "updated_at" : "Mon Mar 15 2010 19:18:41 GMT-0700 (PDT)", "confirmation_sent_at" : "Mon Mar 15 2010 18:44:56 GMT-0700 (PDT)", "last_sign_in_ip" : null, "current_password" : "abc123", "last_sign_in_at" : null, "sign_in_count" : 0, "password_salt" : "3xyzQfMwJeyAZa9tXYZ2", "remember_token" : "ArStvJ7ABzEkzE_feixT", "reset_password_token" : null, "current_sign_in_ip" : null, "remember_created_at" : null", "confirmation_token" :  "C0fuZMksMC7rhOgCxQef", "current_sign_in_at" : null, "email" : "user@example.com", "confirmed_at" : null }

You can now navigate to http://127.0.0.1:3000/users/confirmation?confirmation_token=C0fuZMksMC7rhOgCxQef and confirm the account. Once this is complete you can then goto http://127.0.0.1:3000/users/sign_in to verify that sign is working. Obviously this merely gets you a very bare bones rails app that talks to MongoDB and where I am going to leave it to you. Next steps you will probably want to take will be generating a root controller (e.g. home) and placing links to the sign_in and sign_up pages.

Feb 11 / John Wyles

Google To Offer Fiber Optic Broadband

I just read an article from Google which piqued my interest: Google has announced that they will be offering fiber optic broadband as part of an experiment they are running. This sparked one of those moments where a slow chuckle begins to turn into a rumbling thunder of laughter. You see, as a resident of the City of Mountain View (and I am not the only one), I do not trust that Google will get this experiment any more right than they did the wireless experiment here. I found great humor that this article would even mention the WIFI experiment because it has been a complete and utter failure. Furthermore, I would not trust the service level from a Google broadband connection farther than I can throw my Linksys 54G Wireless router.

As you can see, I have 18 access points within reach of my wireless card at this moment. I believe all of these are utilized, not so much because my neighbors are concerned with information security (which arguably they very much are), but from a complete failure of the Google WIFI experiment. I did not even think I had that many neighbors! I could perceive ditching my wireless internet if the Google WIFI were remotely reasonable. I do not stream video, download large amounts of data, host a site, or do anything thirsty for bandwidth. I imagine at least half my neighbors would probably be in a similar situation and could just as easy ditch their wireless internet were it not for the terrible (read: unavailable) Google WIFI service. All in all, Google fiber optic broadband will likely be no different.

UPDATE: There is an entirely different slant to this news article than I had written about above; namely that Google is becoming a pervasive end-to-end data collection behemoth. The article mentions “connecting remote hospitals” and “helping students” which are flowery ways of painting the fact that Google would like to gain access to a new demographic. For Google to fill in a bigger, and much more detailed, picture it must get its tentacles deeper in to these untapped regions of the country. Similarly, across the pond, in Britain, Google is looking to be a potential investor in giving a boost to Britain’s fiber network. Keeping pace a related slashdot post that asks is Google too big to fail? and raises concern over this same point: Google datasets are getting ever more massive and the potential amount of information gathered within is scary, even to those less paranoid about their online identity.

Feb 10 / John Wyles

PHP Magic Accessors Make Me Want to Punch Babies

As many know PHP have dynamic methods (or magic methods) for producing an environment that, at run-time, is much different than one conceives at first blush. It is largely the inclusion of these magic methods that brought PHP forward and lead to many elegant and inventive solutions. These can be found in nearly every major framework and library that scatter the PHP landscape. Indeed, they let you do very crafty things; take, for example, allowing for the custom dispatch of controller actions in Zend Framework or how Doctrine uses them to perform serialized caching for objects. These examples really can really show off what PHP’s best intentions are. However, like any tool, what it was intended for, and what others are using it for, in practice, can often be at odds. My beef is with the magic accessors and the way I see them employed in many scenarios.

The use of the magic accessors (__get and __set) have allowed for the rapid growth and expansion of objects beyond anyones wildest dreams and now we are paying severely for the bloat and overhead. On top of that, often coupled with this, is the lack of validation of values following overly optimistic assumptions about the values being set. Let me show an example of such a class to make this more clear:

class User
{
    protected $_data=array();

    public function &__get($key)
    {
        $value = null;
        if (isset($this->_data[$key])) {
            $value = $this->_data[$key];
        }

        return $value;
    }

    public function __set($key, $value)
    {
        $this->_data[$key] = $value;
    }

    public function __isset($key)
    {
        return isset($this->_data[$key]);
    }

    public function __unset($key)
    {
        unset($this->_data[$key]);
    }
}

What this now affords developers is the ability to, anywhere in code where they have a User object instance, create arbitrary invalidated values on the User object:

for($i=0; $i<1000000; $i++) {
    array_push($user->foo, new Foo($i));
}
$user->bar = 45.352135;
$user->baz = 'I CAN HAZ ANY VALUE I WANT! MUHAHAHA!';
$user->bat = memcache_get('some_invalid_value_from_mc');
// ...
var_dump(strlen(serialize($user))); // => 134523592

My argument centers around the misuse of these magic accessors, particularly in the case where you are persisting the object (as would most likely be the case for a User object). If you have a value you are putting into an object you should be able to, in a very straightforward manner, validate it (see my post A Tailored Approach to Object Validation). What better way than to explicitly specify an instance variable and a getter and setter method for it? You can still use the magic accessors but perhaps as a catch all for values which seemed to appear out of thin air. Take, for example, the way I think most setups should be done or modeled to closely resemble:

class User
{
    protected $_name;
    protected $_age;
    /* ... */

    public function getAge()
    {
        return $this->_age;
    }

    public function getName()
    {
        return $this->_name;
    }

    public function setAge($age)
    {
        $minimumAge = 0;
        $maximumAge = 130;
        $validator = new Validator_Integer_Between($minimumAge, $maximumAge);
        if (!$validator->valid($age)) {
            throw new ValidationException('The age attribute must be between the values [' . $minimumAge . '] and [' . $maximumAge . ']');
        }

        $this->_age = $age;
    }

    public function setName($name)
    {
        $regEx = "/^[A-Za-z]+$/";
        $validator = new Validator_String_Matches($regEx);
        if (!$validator->valid($name)) {
            throw new ValidationException('The name attribute must match the regular expression pattern [' . $regEx . ']');
        }

        $this->_name = $name;
    }

    public function __get($key)
    {
        throw new Exception('User::__get(' . $key . '): Attempt to get a non-existent attribute [' . $key . ']');
    }

    public function __set($key, $value)
    {
        throw new Exception('User::__set(' . $key . ', ' . $value . '): Attempt to set a non-existent attribute [' . $key . '] to value [' . $value . ']');
    }

    public function __isset($key)
    {
        throw new Exception('User::__isset(' . $key . '): Attempt to check for non-existent attribute [' . $key . ']');
    }

    public function __unset($key)
    {
        throw new Exception('User::__unset(' . $key . '): Attempt to unset a non-existent attribute [' . $key . ']');
    }
}

As you can see any value that “falls through the cracks” will be caught and dealt with. In this way we are able to implement any craziness in the magic accessors, should we ever need do anything “magical”, and use concrete getters and setters so we are able to more readily (and cleanly) allow for the validation of every value set into our object, not to mention its also faster. If you have a million values in your user object you should have at least two million accessor methods (1 million gets, and 1 million sets). Adding a new attribute to the class, creating its getter method, and its setter method forces you to think about what you are doing and whether you need the value or not.