thegoodfellas/blogset-br huggingface dataset:
7.1 passa a ser possivel agrupar varios tipos de exception em um unico bloco catch utilizando o simbolo "|", conforme o exemplo:try { ...} catch (RuntimeException | PDOException $e) { gerar_log($e->getMessage());} catch (Exception $e) { ...}Observe que agora um unico bloco de catch e capaz de capturar excecoes dos tipos RuntimeException, PDOException e seus tipos derivados. Porem, foi mantido um catch separado pois ele realizava outra operacao.Type hint iterableAntes do PHP 7.1, era possivel usar o type hint array ou o type hint Traversable. Porem, quando era especificado array, nao era possivel passar uma variavel Traversable e quando era especificado Traversable, nao era possivel passar uma variavel array. Isso gerava um certo inconveniente, ja que existem situacoes em que uma funcao precisa apenas de uma variavel em que possa iterar com um foreach, independente se e um array ou objeto iteravel.Entao no PHP 7.1 foi criado o type hint especial iterable, que permite informar que um parametro ou um retorno de funcao sera algo iteravel, podendo ser tanto um array como um objeto iteravel.Ajustes na variavel $thisBasicamente o ajuste no PHP 7.1 foi tornar a variavel $this inambiqua e segura. A partir desta versao: nao e permitido que funcoes tenham parametros chamados $this. nao e permitido criar atributos estaticos chamados $this. nao e permitido importar o valor de $this em um escopo pelo comando global. nao e permitido usar a variavel $this como sendo o valor capturado da iteracao de um foreach. nao e permitido atribuir novos valores para a variavel $this via variavel com nome variavel. nao e permitido atribuir novos valores para a variavel $this a partir de uma variavel com referencia para $this. nao e permitido criar variaveis chamadas $this a partir de funcoes que criam variaveis no escopo local, tais como export ou parse_str. a funcao get_defined_vars nunca retornara o valor da variavel $this. o metodo magico __call passa a exibir o valor da variavel $this corretamente. nao e permitido criar variaveis chamadas $this fora de escopos de classes.Criacao de Closure a partir de callableUma das limitacoes de um callback e que para se usar um metodo de uma classe como callback em um escopo fora da classe, o metodo precisa ser publico. Porem, isso nao ocorre se for construida uma Closure com o mesmo proposito.No PHP 7.1, foi criado o metodo estatico Closure::fromCallable, que recebe uma variavel callable e retorna uma Closure correspondente.Alem disso, utilizar Closure e muito mais rapido que um parametro callable, pois o PHP tem um custo alto para determinar que o parametro e, de fato, "chamavel". Por outro lado, uma variavel Closure e por natureza chamavel.Float com mais precisaoNo PHP 7.1, a diretiva de configuracao serialize_precision passa a ter o valor default -1, indicando que sera utilizado o "modo zero" para arredondamento de valores float, que e um algoritimo mais preciso para o proposito. Alem disso, a funcao json_encode passa a usar o tipo de precisao PG (ao inves do EG), garantindo maior precisao de casas decimais para representacao de valores float. Basicamente ele passa de 14 para 17 casas decimais.Melhorias no modulo
CurlForam introduzidas duas melhorias no modulo Curl.A primeira e a criacao das funcoes curl_multi_errno, curl_share_errno e curl_share_strerror, para que cada tipo de resource criado pelo modulo curl (via curl_init, curl_multi_init e curl_share_init) tenham suas proprias funcoes para obter o codigo do ultimo erro e a ultima mensagem de erro.A segunda melhoria e o suporte ao Server Push do HTTP/2. Porem, isso e assunto para outro artigo.
ou o valor da constante. A partir do PHP 7, so e aceito o valor da constante.// Funcionava apenas antes do PHP 7setlocale('LC_NUMERIC', 'pt_BR.utf8');// Funciona sempre (forma ideal)setlocale(LC_NUMERIC, 'pt_BR.utf8');substrQuando a funcao substr recebe o parametro $start maior ou igual ao tamanho da string ela retornava false. A partir do PHP 7, ela passa a retornar uma string vazia.$resultado = substr('abc', 3); // retorna false antes do PHP 7, ou "" a partir do PHP 7mktime e gmmktimeAs funcoes mktime e gmmktime deixaram de receber o parametro $is_dst, que indicava se a data estava com o horario de verao considerado.
para 7.X sem passar pela 6.X? Acontece que no passado houve a implementacao do que seria o PHP 6. O projeto iniciou em 2005, mas acabou sendo "abandonado" em 2010. Chegaram ate a lancar algumas versoes alpha ou beta que cheguei a testar, mas a versao final nunca foi lancada por conta da complexidade que agregou ao nucleo do PHP. A feature que gerou toda a confusao foi o suporte nativo a Unicode. Porem, mesmo abandonando a versao 6, os desenvolvedores da linguagem optaram por lancar algumas das outras features previstas nas versoes 5.3.X em diante mesmo. Com isso, vimos as versoes 5.X terem uma enorme mudanca desde o lancamento da versao 5.0.0 ate as versoes 5.6.X atuais. Afinal, foram mais de uma decada desta versao.Enfim, como o PHP 6 chegou a ser arquitetado e divulgado com um conjunto de features especificas e ate artigos e livros sobre o assunto foram publicados (antes mesmo da versao final ser lancada), optaram por saltar esse numero na contagem de versoes do PHP para evitar confusoes. Para mais detalhes sobre isso, voce pode ler o RFC sobre o proximo nome do PHP.Bem, mas estamos aqui para falar de PHP 7. Estou um pouco enferrujado para escrever artigos, mas vamos ver se esse ano volto ao ritmo.Novidades do PHP 7Primeiramente, vamos dar uma olhada na lista das principais novidades do PHP 7, na ordem de importancia na minha opiniao:Melhoria na performance (PHP 7 e pelo menos duas vezes mais rapido que o 5.6)Reducao significativa de uso de memoriaSuporte a declaracao de tipos escalares e a declaracao de retornos de funcoesMelhoria na hierarquia de ExceptionsMuitos erros fatais convertidos para ExceptionsCriacao do operador "null coalescing"Criacao do operador spaceshipSuporte as Classes anonimasAsserts sem custoRemocao de SAPIs e extensoes velhas e sem suporteGerador de numeros aleatorios seguroArvore de sintaxe abstrataSuporte consistente a 64 bitsAlem destas melhorias, o PHP 7 corrigiu uma enorme lista de bugs conhecidos. Para mais detalhes, voce pode consultar a lista completa de recursos do PHP 7.Algo importante a se destacar e que, quando o numero de revisao mais importante (o primeiro numero) e incrementado, entao aquela versao pode conter recursos que sao incompativeis com as versoes anteriores. Ou seja, um codigo que esta funcionando com PHP 5.6 pode nao funcionar no PHP 7 em algumas ocasioes. Porem, este tipo de inconveniencia e sempre muito debatido e evitado pelos desenvolvedores do PHP. Falaremos sobre estas incompatibilidades a diante.A velocidade do PHP 7Certamente o que mais me chama a atencao no PHP 7 e a velocidade. Nos ultimos anos comecaram a surgir varias iniciativas para utilizar o PHP com mais velocidade. Por exemplo, a iniciativa do Facebook na criacao da linguagem Hack, que e praticamente um fork do PHP, porem executado por uma HHVM atraves de um processo conhecido como "JIT compilation". Antes disso, o proprio Facebook tambem havia tentado o HPHPc, que tinha como objetivo converter codigo PHP em codigo em C, entao compila-lo.Creio que os desenvolvedores do PHP comecaram a se preocupar com o rumo que a linguagem PHP poderia ter, frente as iniciativas do Facebook,
escalar foi informado pelo programador ou nao, entao ela precisa ter valor default NULL e dentro da funcao o valor e checado se vale NULL ou nao.Por fim, mas nao menos importante, e importante dizer que quando um parametro com inducao de tipo escalar e declarado para ser recebido por referencia (ao inves do padrao, que e por copia), entao se a funcao precisou aplicar o casting, ele sera refletido na variavel passada por referencia. Veja o exemplo abaixo para entender:function proximoNumero(int &$a) { return $a + 1;}$meuNumero = "123";var_dump($meuNumero); // vai mostrar: string(3) "123"proximoNumero($meuNumero);var_dump($meuNumero); // vai mostrar: int(123)Note que, mesmo que a funcao nao tenha modificado explicitamente o valor do parametro $a, quando passamos uma variavel com uma string para esta funcao, ela modificou o tipo da variavel para int por causa do casting automatico sofrido durante a execucao da funcao.Declaracao de retornos de funcoesDiferente da inducao de tipo citada na secao anterior (que foi melhorada para suportar tipos escalares no PHP 7), a declaracao de retornos de funcoes e algo totalmente novo no PHP, pois nao era possivel ate entao.A forma como se especifica o tipo de dado retornado por uma funcao e colocando o sinal de dois-pontos seguido do tipo de dado devolvido pela funcao antes da implementacao da funcao (ou seja, antes de abrir chaves da funcao), conforme o exemplo:function soma(int $a, int $b): int { return $a + $b;}Os nomes que podem ser usados como tipos incluem "int", "float", "bool", "string", "array", "self", nomes de classes ou nomes de interfaces.O funcionamento e similar a inducao de tipo, ou seja, uma exception e emitida caso algum valor seja incompativel com o esperado. A diferenca e que neste caso a exception e emitida quando o valor retornado pela funcao e incompativel com o esperado. Isso e avaliado em tempo de execucao. Portanto, nao ocorrera um erro de sintaxe se voce cria uma funcao assim:function teste(): int { return "abc";}Porem, assim que esta funcao for chamada, ela tentara retornar uma string com valor invalido para o tipo de retorno esperado (inteiro), entao a exception sera emitida.A unica observacao a se destacar e que esta declaracao de retorno de funcoes tambem respeita a configuracao definida por "strict_types", ou seja, possui o modo frouxo por padrao, mas pode assumir o modo estrito se desejado.Hierarquia de Exceptions no PHP 7Historicamente, funcoes do PHP sempre utilizaram um mecanismo de erro proprio, que comentei no artigo Controle de Erros em PHP. Porem, no paradigma orientado a objetos e comum a utilizacao de controle de Exceptions, que tambem comentei nos artigos Try catch finally em PHP e Utilizando as Exceptions da SPL do PHP.Para botar ordem na casa, padronizar a forma como o PHP lida com erros fatais, mas manter certa compatibilidade com o legado, o PHP 7 introduziu uma nova hierarquia de exceptions que e a seguinte: A interface Throwable (nova no PHP 7) e a interface base para exceptions e erros. A classe Exception (existente desde o PHP 5.1) passou a implementar a interface Throwable. A classe Error (nova no PHP 7) tambem implementa
a interface Throwable e e disparada no lugar dos antigos mecanismos de disparo de erro considerados fatais (trigger_error). A classe TypeError extende a classe Error e e disparada em casos de erros de tipo. A classe ParserError extende a classe Error e e disparada em casos de erros de parser (ao executar um codigo dinamico com eval, por exemplo). A classe AssertionError extende a classe Error e e disparada em casos de erros de assert. Com esta nova hierarquia, os "catches" existentes nos codigos anteriores ao PHP 7 continuam capturando apenas o que ja capturavam antes, ou seja, as Exceptions. Como a nova classe Error nao extende a classe Exception, entao eles nao sao capturados pelo catch (Exception $e).Porem, agora podemos capturar os erros com um catch (Error $e). E tambem e possivel capturar qualquer coisa, ou seja, montar um catch (Throwable $e), para que tanto Exceptions quanto Errors sejam capturados. Veja os exemplos:try { ...} catch (Exception $e) { // captura apenas exceptions}try { ...} catch (Exception $e) { // captura exceptions aqui} catch (Error $e) { // captura erros aqui}try { ...} catch (Throwable $e) { // captura exceptions ou errors}Uma observacao importante e que a interface Throwable e especial e o programador PHP nao pode implementa-la diretamente. So e possivel extender a classe Exception ou a classe Error, garantindo assim que so havera esses dois tipos basicos de erros.Talvez seja util informar que o construtor da classe Exception mudou de assinatura. Antes ele recebia o parametro $previous do tipo Exception e agora passou a ser do tipo Throwable para ser mais abrangente.Operador null coalescingEste operador e um novo recurso da linguagem muito pratico. Ate o PHP 5.6.X, era comum criarmos instrucoes com operador ternario para checar se um valor foi definido com algo diferente de NULL e atribuir este valor ou algum valor padrao a uma variavel. Isso era feito desta forma:// Usando operador ternario$exemplo = isset($_GET['exemplo']) ? $_GET['exemplo'] : 123;O operador null coalescing permite fazer isso de forma simplificada, atraves da sintaxe usando "??", conforme o exemplo:// Usando operador null coalescing$exemplo = $_GET['exemplo'] ?? 123;Operador SpaceshipO operador spaceship (que tem este nome por parecer uma nave espacial) foi criado especialmente para simplificar a criacao de funcoes usadas como callback para comparacoes. Este tipo de funcao e muito comum quando estamos ordenando um array de uma forma muito peculiar, atraves da funcao usort, por exemplo.O que o operador spaceship faz e retornar um valor -1, 0 ou 1 dependendo da comparacao entre os elementos colocados a esquerda e a direita dele. Quando o elemento da esquerda e considerado menor (ou anterior) ao da direita, o spaceship devolve -1. Quando o elemento da esquerda e considerado maior (ou posterior) ao da direita, o spaceship devolve 1. E quando os elementos da esquerda e da direita sao identicos (ou correspondentes), o spaceship devolve 0 (zero). Veja um exemplo:$a = 1 <=> 2; // $a = -1 pois 1 vem antes do 2$b = 1 <=> 1; // $b = 0 pois 1 eh igual a 1$c = 3 <=> 1; //
$c = 1 pois 3 vem depois do 1$d = 5.4 <=> 5.2; // $d = 1 pois 5.4 vem depois do 5.2$e = "PHP" <=> "Java"; // $e = 1 pois "P" vem depois do "J"$f = "amarelo" <=> "azul"; // $f = -1 pois "m" vem antes do "z"Classes AnonimasO recurso de classes anonimas tem importancia similar as funcoes anonimas que surgiram no PHP 5.3. No caso das funcoes, elas eram criadas sem nome e, normalmente, passadas para outras funcoes como callback. Elas nao eram declaradas em arquivos separados e nem como metodos de alguma classe pois eram usadas em contextos especificos em que nao se utilizaria mais aquela funcao em nenhum outro lugar da aplicacao. Ou entao, eram armazenados em variaveis (ou arrays), para serem passadas quando necessario para outra funcao.O caso das classes e muito semelhante. Cria-se uma classe anonima quando nao ha intencao de se instanciar objetos dessa classe em varios pontos do codigo. E entao, por praticidade, e criada a classe no mesmo ponto do codigo em que se espera receber um objeto dela.E preciso tomar um pouco de cuidado ao usar este recurso, afinal, pode tornar o codigo pouco legivel dependendo do tamanho da classe, alem de causar problemas de arquitetura se usado em locais inadequados. Um exemplo extraido do site do php.net demonstra a utilizacao em um suposto arquivo onde se configura um logger:$util->setLogger(new class { public function log($msg) { echo $msg; }});Ou seja, ao inves de criar uma classe em um arquivo separado e entao instanciar um objeto para passar para o metodo setLogger, foi criado um objeto de uma classe anonima que tem o metodo log. O ideal e que o metodo setLogger esperasse uma interface Logger, por exemplo, entao poderiamos reescrever o codigo criando uma classe anonima, mas que implementa a interface Logger:$util->setLogger(new class implements Logger { public function log($msg) { echo $msg; }});Ou entao criar uma classe anonima que extende outra:$util->setLogger(new class extends BasicLogger { public function log($msg) { echo $msg; }});Tambem e possivel criar classes anoninimas com construtor. Neste casso, a forma como se cria a classe anonima muda um pouco:$a = fopen('/tmp/app.log', 'w');$util->setLogger(new class($a) implements Logger { private $arquivo; public function __construct($arquivo) { $this->arquivo = $arquivo; } public function log($msg) { fwrite($this->arquivo, $msg); }});Asserts sem custoPara quem nao sabe, assert e uma funcao do PHP que ja existe desde o PHP 4. Ele recebe dois parametros: o primeiro e "algo para ser avaliado" e o segundo e uma mensagem de notificacao caso a avaliacao seja falsa. Ou seja, ele e util para se colocar alguns pontos de debug no codigo. Por exemplo, um programador determina que em certo ponto do codigo uma variavel precisaria obrigatoriamente valer mais que 10, segundo sua logica, entao ele coloca a seguinte linha:...assert($a > 10, 'A variavel $a nao e maior que 10');...Assim, caso a afirmativa "$a > 10" retorne false, entao e emitida uma excecao com a mensagem informada. E uma forma simplificada de se fazer isso:...if (($a > 10) === false) { throw new Exception('A variavel $a nao e maior que
10');}...Porem, assert tem uma vantagem sobre o if, que e a posssibilidade de liga-lo e desliga-lo via configuracoes do PHP. Assim, voce pode deixar esses debugs ligados em ambiente de desenvolvimento e teste, mas desligado em producao.Importante: note que o assert nao foi feito para se avaliar condicoes que podem ser modificadas pelo usuario final. Nao devemos colocar um assert checando se uma variavel recebida por GET ou POST possui valor maior que 10, por exemplo. Ou seja, precisam ser condicoes que o programador entende que so daria errado se ele (programador) ou outro colega de trabalho usasse sua funcao ou classe de forma incorreta e que isso deveria ser detectado durante o proprio desenvolvimento. Por isso e que em producao essa checagem (em teoria) nunca precisaria ser feita.O assert tambem podia receber uma string com um codigo PHP a ser avaliado. Como o exemplo abaixo:...assert('is_callable($f)', "A variavel precisa ser invocavel");...A vantagem de usar uma string e que, quando voce desliga as checagens de asserts (em producao), o codigo nao precisa executar a funcao is_callable($f) para obter um valor booleano que so depois sera ignorado pela funcao assert. Isso por causa da ordem com que as coisas precisam ocorrer para a funcao ser executada, ou seja, antes do assert ser executado, todas as expressoes passadas nos parametros precisam ser processadas primeiro. Mas no caso de strings, elas ja sao valores prontos para serem passados para o assert e entao o proprio "assert" e que pega essa string e a executa (caso ele esteja habilitado). Portanto, se a instrucao que esta sendo avaliada no assert for muito custosa (em tempo ou memoria), entao haveria um ganho em ambiente de producao, onde o assert estaria desligado.Finalmente podemos dizer que a grande mudanca no assert no PHP 7 foi que ela deixou de ser uma funcao e passou a ser uma construcao da linguagem e que, mesmo passando as expressoes sem estarem na forma de string, o seu valor nao sera processado caso a configuracao de asserts estiver desligado (por isso, passaram a ser "sem custo"). Isso e bom, pois montar expressoes dentro de string e arriscada como instrucoes eval e precisam de cuidados de escape de alguns caracteres em determinadas circunstancias. Alem disso, no PHP 7 a construcao assert tambem passou a permitir receber uma excecao no lugar de uma mensagem, como no exemplo:...assert($a > 10, new Exception('A variavel $a nao e maior que 10'));...Remocao de SAPIs e extensoes velhas e sem suporteQuanto a remocao de SAPIs e extensoes velhas e sem suporte, o que considero mais significativo e a remocao da extensao "mysql". A partir do PHP 7 passa a ser necessario utilizar MySQLi, PDO ou, se voce for maluco, pode implementar sua propria biblioteca para comunicar com o MySQL pelo protocolo binario, via socket numa porta especifica, usando a funcao fsockopen. Para continuar usando a extensao "mysql", precisa instalar via Pecl: Extensao MySQL no PeclOutra extensao que foi removida foi a ereg. Agora e necessario usar as funcoes PCRE, como mostrei no artigo Expressoes Regulares em PHP.Para mais informacoes do que saiu
7 trouxe muitas novidades e uma excelente melhoria em performance. As principais caracteristicas foram discutidas neste artigo, mas voce tambem pode continuar lendo este outro com outras novidades do PHP 7.E, para ainda mais informacoes, veja a Lista completa de novidades e incompatibilidades no PHP 7
IntroducaoNo artigo sobre Expressoes Regulares em PHP, vimos os conceitos basicos sobre expressoes regulares. Porem, algo que pode gerar certa confusao e sobre a criacao de uma expressao regular que verifique se determinada string e um numero presente em um determinado intervalo numerico (range). Neste artigo veremos qual e o problema e e apresentada uma classe que gera a expressao regular de um intervalo numerico.O problema do range em RegExpO problema de se expressar intervalos numericos na forma de expressoes regulares e que expressoes regulares sao baseadas em strings com tamanhos especificos, enquanto intervalos numericos seguem uma logica matematica sequencial.Embora seja muito simples criar uma expressao regular para um intervalo simples como "um numero de 3 a 7" (expresso na forma /^[3-7]$/), o mesmo nao vale para um intervalo como 13 a 27.Se voce pensou em algo como /^[13-27]$/, voce ja errou feio. Esta expressao casaria apenas strings contendo um unico digito que pode ser "1", ou algum digito no intervalo de "3" a "2", ou o "7". Como o 3 e maior que 2, entao a expressao regular nem chega a ser compilada. Nem preciso dizer que a expressao nao vai funcionar.Se voce pensou na expressao /^[1-2][3-7]$/, entao esta dizendo que o primeiro digito pode ser 1 ou 2, e o segundo digito pode ser algum entre 3 e 7. Isso significa que a expressao nao casaria os numeros 18, 19, 20, 21 e 22, entao nao funciona.Por outro lado, se voce pensou na expressao /^[1-2][0-9]$/, entao esta dizendo que o primeiro digito pode ser 1 ou 2, e o segundo digito pode ser algum entre 0 e 9. Isso significa que a expressao casaria os numeros 18, 19, 20, 21 e 22, porem, tambem casaria o 28 e o 29, que nao fazem parte do intervalo, portanto, tambem nao funciona.Mas se voce pensou em /^(13|14|15|16|17|18|19|20|21|22|23|24|25|26|27)$/, significa que voce e bem preguicoso, mas resolve o problema.Mas a forma mais correta de se montar a expressao regular para casar numeros no intervalo de 13 a 27 e com /^(1[3-9]|2[0-7])$/. Ou seja, se o primeiro digito for 1, ele deve ser seguido de algum digito entre 3 e 9, mas se o primeiro digito for 2, ele deve ser seguido de algum digito entre 0 e 7. Isso contempla todos numeros entre 13 e 27.Poxa, parece facil agora? Entao experimente montar uma expressao que contemple o intervalo de 222100 e 272099, por exemplo. A expressao e realmente bem mais complexa.Na verdade, a melhor forma de se validar que um numero esta dentro de um intervalo e com os operadores de maior ou menor. Mas se o seu numero estiver representado em uma string e ela tiver muitos digitos (ser maior que PHP_INT_MAX, por exemplo), talvez voce precise usar a funcao bccomp da extensao BCMath para comparar sem perda de precisao. Porem, as vezes seu sistema ja esta preparado para receber uma expressao regular em determinado ponto, e voce precisa validar um intervalo complexo. Neste caso, sugiro que utilize a classe abaixo para gerar a expressao pra voce.Classe RangeRegexObservacao: esta classe requer a extensao