Hoje vou dar uma pincelada sobre algo que eu queria abordar faz tempo, mas como me afastei do 
PHP por conta da correria do trabalho no dia-a-dia, demorei... Mas nunca é tarde. 
O exemplo é bem simples e clássico, solução pra um problema e desejo antigo: carregar dados numa página web sem refresh. Eu sempre ouvia falar do AJAX e, apesar de ter começado minha carreira fazendo sites, só fui vê-lo em 2006, mas a primeiras coisas que estou fazendo com ele pra testar foram só recentemente. E agora que entendi quero compartilhar - eu já até estudei o Adobe Flex e cada um (Flex e AJAX) tem suas vantagens, mas a principal do AJAX é ser mais leve, pois usa os próprios bons e velhos HTML, XML e JavaScript, sem precisar da instalação de plugins como o do Flash Player que o Flex precisa. 
Como eu disse, é um exemplo simples e clássico de seleção de cidades, onde numa caixa você seleciona o estado desejado e na de baixo a cidade numa lista criada dinamicamente com as cidades de cada estado selecionado. 
Pra começar, vamos à criação do nosso banco de dados no MySQL - eu peguei parte das tabelas de um banco no qual estou trabalhando, bem simples, foi um dump mesmo que fiz no phpMyAdmin do meu servidor on-line, já com os dados pro exemplo. Veja:
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
CREATE DATABASE `cidades` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 
USE `cidades`;
CREATE TABLE IF NOT EXISTS `cidades` ( 
  `id_cidade` int(11) NOT NULL auto_increment, 
  `id_uf` int(11) NOT NULL, 
  `nome` varchar(35) NOT NULL, 
  `cep_principal` char(10) NOT NULL, 
  `is_capital` tinyint(1) NOT NULL default '0', 
  `sigla` varchar(3) NOT NULL, 
  PRIMARY KEY  (`id_cidade`), 
  UNIQUE KEY `sigla` (`sigla`) 
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;
INSERT INTO `cidades` (`id_cidade`, `id_uf`, `nome`, `cep_principal`, `is_capital`, `sigla`) VALUES 
(1, 1, 'Cuiabá', '78000-000', 1, 'CBA'), 
(2, 1, 'Sinop', '78550-000', 0, 'SNP'), 
(3, 1, 'Alta Floresta', '78580-000', 0, 'AFL'), 
(4, 1, 'Lucas do Rio Verde', '78455-000', 0, 'LRV'), 
(5, 1, 'Rondonópolis', '78700-000', 0, 'ROO'), 
(6, 2, 'Cascavel', '85800-000', 0, 'CVL');
CREATE TABLE IF NOT EXISTS `paises` ( 
  `id_pais` int(11) NOT NULL auto_increment, 
  `sigla` varchar(5) NOT NULL, 
  `nome` varchar(30) NOT NULL, 
  PRIMARY KEY  (`id_pais`), 
  UNIQUE KEY `sigla` (`sigla`) 
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `paises` (`id_pais`, `sigla`, `nome`) VALUES 
(1, 'BRA', 'Brasil');
CREATE TABLE IF NOT EXISTS `uf` ( 
  `id_uf` int(11) NOT NULL auto_increment, 
  `id_pais` int(11) NOT NULL, 
  `sigla` char(2) NOT NULL, 
  `nome` varchar(25) NOT NULL, 
  PRIMARY KEY  (`id_uf`), 
  UNIQUE KEY `sigla` (`sigla`) 
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
INSERT INTO `uf` (`id_uf`, `id_pais`, `sigla`, `nome`) VALUES 
(1, 1, 'MT', 'Mato Grosso'), 
(2, 1, 'PR', 'Paraná'), 
(3, 1, 'MS', 'Mato Grosso do Sul');
Criado o banco, vamos ao PHP. Eu usei o próprio Gedit do Ubuntu (se você usa o ambiente KDE do Kubuntu - o qual eu também tenho instalado por curiosidade, gostei, achei legal e muito bonito, embora não seja tão prático como o GNOME - use o Kate, mas tem que verificar a compatibilidade com UTF-8).
Voltando ao assunto, o primeiro arquivo que criamos é o dados.php, que contêm a classe de conexão ao banco e seleção da base, conforme abaixo:
<?php 
  class dados 
  { 
    //Propriedades/parâmetros do objeto de conexão 
    public $host = "localhost"; 
    public $user = "cidades"; 
    public $senha = "cidades"; 
    public $db = "cidades";
    public function get_conexao() 
    { 
      //Conecta ao MySQL e seleciona o banco de dados 
      $cnx = @mysql_connect($this->host, $this->user, $this->senha) or die("<pre>(!) Falha ao conectar ao banco de dados.</pre>"); 
      @mysql_select_db($this->db, $cnx) or die("<pre>(!) Falha ao selecionar banco de dados. ".str_replace('..', '.', mysql_error().'.')."</pre>"); 
    } 
  } 
?>
Eu usei funções nativas e simples do PHP na conexão pra ficar mais legível. Ah, e se você notou, no PHP a classe deve ter o mesmo nome do arquivo que a contém. 
Bem, agora vamos criar o arquivo cidades_obj.php, que será a nossa classe de objeto que representa e guarda os dados de cada cidade selecionada. Note que as propriedades do objeto são um espelho dos campos do banco de dados pra, também, ficar mais legível:
<?php 
  class cidades_obj 
  { 
    //Propriedades do objeto cidades 
    public $id_cidade; 
    public $id_uf; 
    public $nome; 
    public $cep_principal; 
    public $is_capital; 
    public $sigla; 
  } 
?>
Ok, agora vamos à classe que pega os dados no banco e joga numa lista de objetos (ou seja, a lista com cada cidade representada pelo objeto que criamos acima). Lista de objetos é pra ficar mais bonitinho, mas é um array mesmo. O nosso arquivo é o cidades.php. No início dele temos as propriedades que usaremos como parâmetros e na função get_cidades usamos as funções clássicas pra trabalhar com querys do MySQL no PHP:
<?php 
  include_once("dados.php"); 
  include_once("cidades_obj.php");
  class cidades 
  { 
    //Propriedados/parâmetros do objeto de consulta de cidades 
    public $id_cidade = 0; 
    public $id_uf = 0; 
    public $nome = ''; 
    public $cep_principal = ''; 
    public $is_capital = false; 
    public $sigla = '';
    //Contador de resultados 
    public $count = 0;
    public function get_cidades() 
    { 
      //Seleciona cidades no banco 
      $sql = "SELECT * FROM cidades"; 
      $sql .= " WHERE id_cidade > 0";
      //Verifica parâmetros 
      if ($this->id_cidade > 0) $sql .= " AND id_cidade = ".$this->id_cidade; 
      if ($this->id_uf > 0) $sql .= " AND id_uf = ".$this->id_uf; 
      if (strlen($this->nome) > 0) $sql.= " AND nome LIKE '%".$this->nome."%'"; 
      if (strlen($this->cep_principal) > 0) $sql.= " AND cep_principal = '".$this->cep_principal."'"; 
      if ($this->is_capital == true) $sql .= " AND is_capital"; 
      if (strlen($this->sigla) > 0) $sql.= " AND sigla = '".$this->sigla."'";
      $sql .= " ORDER BY nome ASC";
      //Conecta ao banco e abre a query 
      $dados = new dados(); 
      $dados->get_conexao(); 
      $rs = mysql_query($sql); 
      $this->count = 0;
      //Passa resultados pra um array do objeto cidades 
      while ($reg = mysql_fetch_array($rs)) 
      { 
        $cidade = new cidades_obj(); 
        $cidade->id_cidade = $reg['id_cidade']; 
        $cidade->id_uf = $reg['id_uf']; 
        $cidade->nome = $reg['nome']; 
        $cidade->cep_principal = $reg['cep_principal']; 
        $cidade->is_capital = $reg['is_capital']; 
        $cidade->sigla = $reg['sigla']; 
        $a[] = $cidade; 
        $this->count++; 
      }
      //Fecha conexão 
      mysql_close();
      //Retorna lista de cidades 
      return $a; 
    } 
  } 
?>
Já temos o objeto que trará nossos resultados, agora vamos ler o array gerado pela classe acima e escrever o nosso XML no arquivo cidades.xml.php. Note que no início do arquivo instanciamos o objeto da classe acima e mais abaixo usamos a biblioteca DOMDocument do PHP5 pra gerar o XML:
<?php 
  include_once("cidades.php");
  //Chama objeto cidades passando parâmetro por UF 
  $cidades = new cidades(); 
  $cidades->id_uf = $_POST["id_uf"]; 
  $lst = $cidades->get_cidades();
  //Verifica se o array tem resultados 
  if ($cidades->count > 0) 
  { 
    //Cria XML 
    $xml = new DOMDocument("1.0", "UTF-8"); 
    $xml->preserveWhiteSpace = false; 
    $xml->formatOutput = true;
    //Insere nó principal 
    $root = $xml->createElement("cidades");
    //Varre o array 
    foreach($lst as $city) 
    { 
      //Atribui variáveis pra criar campos com o valor de cada registro 
      $id_uf = $xml->createElement("id_uf", $city->id_uf); 
      $id_cidade = $xml->createElement("id_cidade", $city->id_cidade); 
      $sigla = $xml->createElement("sigla", utf8_encode($city->sigla)); 
      $nome = $xml->createElement("nome", utf8_encode($city->nome));
      //Cria nó de registro 
      $cidade = $xml->createElement("cidade");
      //Adiona campos com os valores 
      $cidade->appendChild($id_uf); 
      $cidade->appendChild($id_cidade); 
      $cidade->appendChild($sigla); 
      $cidade->appendChild($nome);
      //Adiciona o registro ao nó prncipal 
      $root->appendChild($cidade); 
    }
    //Fecha a TAG do nó principal 
    $xml->appendChild($root);
    //Imprime o XML na tela 
    Header("Content-Type: text/xml"); 
    echo $xml->saveXML(); 
  } 
?>
O resultado gerado pela função acima é um arquivo XML mesmo como este:
<?xml version="1.0" encoding="UTF-8"?> 
<cidades> 
  <cidade> 
    <id_uf>1</id_uf> 
    <id_cidade>3</id_cidade> 
    <sigla>AFL</sigla> 
    <nome>Alta Floresta</nome> 
  </cidade> 
  <cidade> 
    <id_uf>2</id_uf> 
    <id_cidade>6</id_cidade> 
    <sigla>CVL</sigla> 
    <nome>Cascavel</nome> 
  </cidade> 
  <cidade> 
    <id_uf>1</id_uf> 
    <id_cidade>1</id_cidade> 
    <sigla>CBA</sigla> 
    <nome>Cuiabá</nome> 
  </cidade> 
  <cidade> 
    <id_uf>1</id_uf> 
    <id_cidade>4</id_cidade> 
    <sigla>LRV</sigla> 
    <nome>Lucas do Rio Verde</nome> 
  </cidade> 
  <cidade> 
    <id_uf>1</id_uf> 
    <id_cidade>5</id_cidade> 
    <sigla>ROO</sigla> 
    <nome>Rondonópolis</nome> 
  </cidade> 
  <cidade> 
    <id_uf>1</id_uf> 
    <id_cidade>2</id_cidade> 
    <sigla>SNP</sigla> 
    <nome>Sinop</nome> 
  </cidade> 
</cidades>
Por fim, vamos à nossa página com a seleção das cidades por estado. Eu dei ao arquivo o nome de idades.html.php seguindo o padrão que você deve ter percebido acima: ".xml.php" pra XML, "_obj.php" pra objeto (só criei com "_" por causa no nome da classe do objeto), só ".php" pra classe que pega os dados, e agora .html.php" pro arquivo que será visível mesmo - no meu ponto de vista este padrão ajuda a identificar pelo nome o propósito de de cada arquivo. 
Bem, este último arquivo é o maior e mais complexo, onde vamos trabalhar com o AJAX mesmo, isso significa muito JavaScript, pois como o próprio nome já diz é Asynchronous Javascript And XML. Temos as funções todas no JavaScript para instanciar o AJAX, ler, fazer a consulta no nosso XML e imprimir os resultados na tela. Eis o código completo:
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" > 
<html> 
  <head> 
    <title>Selecione a cidade</title> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <!-- ESTILOS DA PÁGINA --> 
    <style type="text/css"> 
      body 
      { 
        background-color: #FFFFFF; 
        font-family: arial, verdana, sans-serif; 
        font-size: 10pt; 
      } 
      .Fonte8 
      { 
        font-size: 8pt; 
      } 
      .Fonte12 
      { 
        font-size: 12pt; 
      } 
    </style>
    <!-- CÓDIGOS DO AJAX --> 
    <script language="JavaScript"> 
      function Dados(valor) 
      { 
        //Verifica se o navegador tem suporte a AJAX e qual o tipo de objeto AJAX ele usa 
        try 
        { 
          ajax = new ActiveXObject("Microsoft.XMLHTTP"); 
        } 
        catch(e) 
        { 
          try 
          { 
            ajax = new ActiveXObject("Msxml2.XMLHTTP"); 
          } 
          catch(ex) 
          { 
            try 
            { 
              ajax = new XMLHttpRequest(); 
            } 
            catch(exc) 
            { 
              alert("Este navegador não tem recursos para uso do AJAX!"); 
              ajax = null; 
            } 
          } 
        }
        //Se tiver suporte a AJAX 
        if(ajax) 
        { 
          //Deixa apenas o elemento 1 no option, os outros são excluídos 
          document.forms[0].listCidades.options.length = 1; 
          idOpcao  = document.getElementById("opcoes");
          if (valor == -1) 
          { 
            //Desabilita a lista de cidades 
            document.forms[0].listCidades.disabled="disabled"; 
            idOpcao.innerHTML = "Selecione um estado na lista."; 
          } 
          else 
          { 
            //Define a chamada via POST ao XML criado pelo PHP com as cidades 
            ajax.open("POST", "cidades.xml.php", true); 
            ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            ajax.onreadystatechange = function() 
            { 
              //Enquanto estiver processando emite a mensagem de aguarde 
              if(ajax.readyState == 1) 
              { 
                idOpcao.innerHTML = "Aguarde..."; 
              }
              //Após ser processado chama função processXML que vai varrer os dados 
              if(ajax.readyState == 4 ) 
              { 
                if(ajax.responseXML) 
                { 
                  processXML(ajax.responseXML); 
                } 
                else 
                { 
                  //Caso não consiga ler o arquivo XML emite a mensagem e desabilita a lista de cidades 
                  idOpcao.innerHTML = "Cidades não encontradas."; 
                  document.forms[0].listCidades.disabled="disabled"; 
                } 
              } 
            } 
          }
          //Passa o código do estado escolhido como parâmetro pro POST e envia 
          var params = "id_uf=" + valor; 
          ajax.send(params); 
        }
        function processXML(obj) 
        { 
          //Pega a TAG cidade 
          var dataArray = obj.getElementsByTagName("cidade");
          //Verifica o total de elementos contidos na TAG cidade 
          if(dataArray.length > 0) 
          { 
            //Percorre o arquivo XML para extrair os dados 
            for(var i = 0 ; i < dataArray.length ; i++) 
            { 
              var item = dataArray[i];
              //Contéudo dos campos no arquivo XML 
              var sigla =  item.getElementsByTagName("sigla")[0].firstChild.nodeValue; 
              var nome = item.getElementsByTagName("nome")[0].firstChild.nodeValue;
              idOpcao.innerHTML = "Selecione a cidade.";
              //Cria um novo option dinamicamente 
              var novo = document.createElement("option");
              //Atribui um ID a esse elemento 
              novo.setAttribute("id", "opcoes");
              //Atribui valor e texto 
              novo.value = sigla; 
              novo.text = sigla + " - " + nome;
              //Adiciona o novo elemento 
              document.forms[0].listCidades.options.add(novo); 
            } 
            //Habilita a lista de cidades 
            document.forms[0].listCidades.disabled=""; 
          } 
          else 
          { 
            //Caso o XML volte vazio, exibe a mensagem abaixo e desabilita a lista de cidades 
            idOpcao.innerHTML = "Cidades não encontradas."; 
            document.forms[0].listCidades.disabled="disabled"; 
          } 
        } 
      } 
    </script>
  </head>
  <body onload="document.forms[0].listCidades.disabled='disabled'"> 
    <span class="Fonte12"><b>Selecione a cidade</b></span><br /> 
    <span class="Fonte8">Tecnologia MySQL/OOP-PHP/AJAX</span> 
    <br /><br />
    <form name="frmAjax"> 
      UF:  
      <select name="listEstados" onChange="Dados(this.value);"> 
        <option value="-1">Selecione o estado.</option> 
        <option value="1">Mato Grosso</option> 
        <option value="2">Paraná</option> 
        <option value="3">Mato Grosso do Sul</option> 
      </select> 
      <br><br> 
      Cidade:  
      <select name="listCidades" onChange="if (this.value != '0') { alert('Você selecionou ' + this.value + '.'); }"> 
        <option id="opcoes" value="0">Primeiro selecione o estado.</option> 
      </select> 
    </form> 
    <a href="#" onclick="history.back()">Voltar</a> 
</body> 
</html>
O HTML é normal. Preste atenção aos nomes dos elementos pra poder chamá-los no JavaScript e às variáveis que armazenam os dados. Aquela verificação do suporte ao AJAX é por conta das diferenças de padrões - muita gente ainda não acordou pra vida e anida usa Microsoft Internet Explorer 6, e bem desatualizado, por isso nossa página pode não funcionar direito pra eles; além do que esta verificação é necessária porque o Windows Internet Explorer, me refiro já a algo mais considerável, que é o IE7 e o IE8, trabalha com AJAX via ActiveX, enquanto o Firefox, o Safari e o Chrome têm isso um pouco mais 'nativo' (não verifiquei o Opera). 
Seguindo, nas últimas linhas da função Dados note que passamos o parâmetro com o código da UF que é verifiado la no $_POST do arquivo XML fazendo o nosso filtro. E na função proccessXML lemos o resultado retornado do XML chamado na função anterior, e preenchemos os valores da lista de cidades de acordo com eles. 
Eu ignorei a tabela de países e criei a lista de estados fixa no HTML pra agilizar o exemplo. 
Enfim, é bem resumido, mas espero que tenha sido proveitoso. Se você quiser como ficou o meu exemplo funcionando, clique aqui:  
http://pedro-araujo.com/tarefas/cidades.html.php
Referências: