Que dicas gerais você tem para jogar golfe no PHP? Estou procurando idéias que possam ser aplicadas aos problemas de código de golfe em geral, que sejam pelo menos um pouco específicos do PHP (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.
37
Respostas:
Entenda como variáveis e espaços em branco interagem com as construções de linguagem do PHP.
No meu tempo de jogo (reconhecidamente curto), eu descobri que as construções de linguagem do PHP (por exemplo, eco, retorno, por enquanto, etc.) se comportam de maneira menos que intuitiva ao interagir com variáveis e espaços em branco.
echo$v;
, por exemplo, é perfeitamente válido, como sãoreturn$v;
e outras construções semelhantes. Essas pequenas reduções no espaço em branco podem levar a uma diminuição cumulativa significativa no comprimento.Porém, lembre-se de que as variáveis anteriores às construções de linguagem requerem um espaço depois, como no exemplo a seguir:
Por
AS
ser uma construção de linguagem, um espaço não é necessário antes da variável$b
, mas se alguém omitir o espaço antes dela , resultando em$aAS
, isso seria analisado como um nome de variável e levaria a um erro de sintaxe.fonte
foreach($a[1]as$b)
não precisa de espaço em branco. Não se trata de construções e variáveis de linguagem, mas de espaços entre caracteres de palavras de palavras diferentes.echo $a+5." text"
não funcionará porque o PHP acha que.
é um ponto decimal para o arquivo5
. Para fazê-lo funcionar, você precisaria adicionar um espaço como este: #echo $a+5 ." text"
echo$a+5," text";
. Aecho
construção permite que você passe vários parâmetros. onde alguém teria que escreverecho"result: ".($a+5)."!";
, você pode escreverecho"result: ",$a+5,"!";
. De fato, passar vários parâmetros para umecho
é uma micro-otimização, pois o código será executado um pouquinho mais rápido (já que você não concatena a saída, mas a envia separadamente). Para desafios sobre como escrever o código mais rápido, isso pode ajudar um pouquinho.echo
, mas não comprint
(o que você precisa se você o colocar dentro de uma expressão:echo
é uma construção pura, sem valor de retorno, enquantoprint
pode funcionar como uma função: não requer parênteses, mas sempre retornaint(1)
.print
.Use cordas com sabedoria.
Esta resposta é dupla. A primeira parte é que, ao declarar strings, você pode utilizar a conversão implícita do PHP de constantes desconhecidas em strings para economizar espaço, por exemplo:
O
@
é necessário para substituir as advertências Isto irá produzir. No geral, você acaba com uma redução de um caractere.é que, às vezes, pode ser eficiente em termos de espaço definir uma variável para o nome de uma função usada com frequência. Normalmente, você pode ter:
Mas quando jogar golfe, isso pode ser reduzido facilmente para:
Com apenas duas instâncias de "preg_match", você salva apenas um único caractere, mas quanto mais você usa uma função, mais espaço economiza.
fonte
E_DEPRECATED
) são aceitáveisphp.ini
arquivoVocê nem sempre precisa escrever verificações condicionais. Por exemplo, algumas estruturas usam isso na parte superior de seus arquivos para bloquear o acesso:
Ou em funções normais
ao invés de
fonte
Use sintaxe de matriz curta
Desde o PHP 5.4, os arrays podem ser declarados usando colchetes (assim como JavaScript), em vez da
array()
função:Ele salvará cinco bytes.
Mas pode custar bytes se você tiver "buracos" em uma matriz associativa:
a desvantagem ocorre um pouco mais tarde se você puder preencher os furos com valores "vazios":
fonte
[,$a,$b,$c]=$argv;
.Use $ {0}, $ {1}, $ {2}, ... em vez de $ a [0], $ a [1], $ a [2], ...
A menos que você esteja executando uma manipulação de matriz, a maioria das referências a um índice de matriz
$a[$i]
pode ser substituída simplesmente$$i
. Isso é verdade mesmo se o índice for um número inteiro, pois números inteiros são nomes de variáveis válidos no PHP (embora literais exijam colchetes, por exemplo${0}
).Considere a seguinte implementação da torneira Rabonowitz Wagon:
Isso pode ser aprimorado em 6 bytes, simplesmente substituindo as duas referências de matriz
$a[$g]
por$$g
:fonte
Aprenda um grande subconjunto das funções da biblioteca .
A biblioteca do PHP é bastante grande e oferece várias funções convenientes que podem reduzir bastante várias tarefas. Você pode pesquisar sempre que tentar fazer algo, mas além de perder tempo, pode não encontrar nada que corresponda à sua pesquisa específica. A melhor maneira é apenas se familiarizar com a biblioteca e memorizar os nomes das funções e o que elas fazem.
fonte
Funções em execução dentro de strings.
Tente o seguinte:
Ou tente o seguinte:
Isso funciona apenas com strings usando
""
e heredocs (NÃO confunda com nowdocs).O uso de funções aninhadas só é possível dentro de heredocs aninhados (ou você encontrará erros de análise)!
fonte
you will run into parse errors
Eu não posso ler isso sozinho? Como o irritante mecanismo Zend coloca isso juntodiversão com tipmarks
!!$foo
transformará qualquer valor verdadeiro paratrue
(ou1
na saída), valores falsos (0, cadeia vazia, matriz vazia) parafalse
(ou saída vazia)Isso raramente será necessário no código golf, pois na maioria dos casos em que você precisa de um valor booleano, existe um elenco implícito de qualquer maneira.
(int)$foo
pode ser escrito como$foo|0
oufoo^0
, mas pode precisar de parênteses.Para booleanos e strings,
$foo*1
ou+$foo
pode ser usado para converter para int.10
, você pode acrescentar um zero:*10
->.0
. Mas neste caso, o PHP pegará o ponto como ponto decimal e reclamará. (É diferente se você tiver uma quantidade variável de zeros em uma string.)join
vez deimplode
.Se você não precisa de um delimitador, não o use:
join($a)
faz o mesmo quejoin('',$a)
$s=a;$s++;
produz$s=b;
. Isso funciona com caracteres maiúsculos e minúsculos.$s=Z;$s++;
resulta em$s=AA;
.Isso também funciona com maiúsculas e minúsculas:
aZ
parabA
,A1
paraA2
,A9
paraB0
ez99Z
paraaa00A
.Decremento não funciona em seqüências de caracteres. (E isso não acontece
NULL
).De volta ao PHP 3,
$n="001";$n++;
produzido$n="002";
. Estou um pouco triste por terem removido isso.Qualquer que seja o seu golfe: tenha sempre em mãos a tabela de precedência do operador .
fonte
Use atalhos
No código normal, é uma boa prática usar
<?php
e?>
. No entanto, este não é um código normal - você está escrevendo um código de código de golfe. Em vez de<?php
escrever<?
. Em vez de<?php echo
escrever<?=
. Não digite?>
no final - é totalmente opcional. Se você precisar?>
de algum motivo (por exemplo, para gerar texto e for mais curto de alguma forma, ou algo assim, não coloque um ponto-e-vírgula antes dele - ele não é necessário, pois?>
implica ponto e vírgula.Errado (definitivamente muito longo):
Corrigir:
fonte
-r
bandeira ( que é gratuita ), você não possui tags (e você não tem permissão para usá-las).loop através de cordas
pode ser feito com 26 bytes ou com 24 a 18:
$a&$b
faz um bit a bit E no (códigos ASCII de) os personagens$a
e$b
e resulta em uma cadeia que tem o mesmo comprimento que o mais curto de
$a
e$b
.fonte
ord($s[$p++])
como alternativafor(;$s+=ord($argv[++$i])%32?:die($s==100););
contrafor(;$c=$argv[++$i];)$s+=ord($c)%32;echo$s==100;
nesta questão codegolf.stackexchange.com/questions/116933/...~
para casos que você está trabalhando apenas com dígitos~$c
abordagem.Use operadores ternários
pode ser abreviado para isso:
Mais curto, hein?
fonte
a?aa:ab?aba:abb:b
avalia(a?aa:ab)?(aba):(abb)
ou algo assim.$a?:$b
é o mesmo que$a?$a:$b
.||
lança para booleano em PHP.por qualquer outro nome ... aliases de função
usar ...
join
ao invés deimplode
chop
em vez dertrim
(chop
em PERL é diferente!)die
ao invés deexit
fputs
ao invés defwrite
is_int
em vez deis_integer
ouis_long
is_real
em vez deis_float
ouis_double
key_exists
ao invés dearray_key_exists
mysql
ao invés demysql_db_query
... para nomear os aliases mais importantes. Dê uma olhada em http://php.net/aliases para obter mais informações.
fonte
die
funciona com e sem parâmetros?die(1)
sairá do programa com código de erro1
(não totalmente certo disso; precisa de teste);die
sairá com código0
edie("Hello")
sairá com código0
após a impressãoHello
.Matrizes associativas podem ser mescladas com o
+
operador.Ao invés de:
Usar:
Observe que o
+
operador também trabalha com matrizes indexadas, mas provavelmente não faz o que você deseja.fonte
+
, desde que os índices sejam distintos. Caso contrário, os valores da primeira matriz serão substituídos pelos da segunda (assim como array_merge). A diferença:+
não reordena índices.array_flip vs array_search
usar
ao invés de
salvar 1 Byte em matrizes onde a ocorrência de cada valor é única
fonte
alguns fatos interessantes sobre variáveis variáveis
Eu só tinha que compartilhá-los (mesmo antes de verificar que pelo menos um deles ajuda no golfe):
$x=a;$$x=1;$x++;$$x=2;echo"$a,$b";
imprime1,2
mas outras operações aritméticas não funcionam com letras.
$a=1;$$a=5;$a++;$$a=4;${++$a}=3;echo${1},${2},${3};
prints543
.[0-9a-zA-Z_]
para nomes de variáveis, mas TODAS as strings:$x="Hello!";$$x="Goodbye.";echo${"Hello!"};
imprimeGoodbye.
.[a-zA-Z_][a-zA-Z_0-9]*
nomes de variáveis, requer chaves para uso literal.$$x=1
conjuntos${NULL}
, que é o mesmo que${false}
e${""}
.$a=1;$$a=5;
não apenas define${1}
, mas também${true}
.mais uma, a mais estranha que encontrei até agora: tente
$a=[];$$a=3;echo${[]};
. Sim, ele imprime3
!A razão para a maior parte disso: os nomes de variáveis são sempre avaliados em seqüências de caracteres.
(Obrigado @Christoph por apontar.)
Então, o que você obtém quando você
print
ouecho
a expressão, é o que você obtém como nome da variável.fonte
[]
converte emArray
:${[]} = 5;echo $Array;
impressões5
. Tenho certeza que você sabe isso, mas ele pode não ser óbvio para todos :)quebras de linha
se a saída exigir quebras de linha, use uma quebra de linha física (1 byte) em vez de
"\n"
Isso também oferece um possível benefício para você escolher entre aspas simples e duplas.
fonte
evite citações sempre que possível
O PHP lança implicitamente palavras desconhecidas para cadeias literais.
$foo=foo;
é o mesmo que$foo='foo';
(supondo quefoo
não seja uma palavra-chave ou uma constante definida):$foo=echo;
não funciona.MAS:
$p=str_pad;
faz; e$p(ab,3,c)
avalia paraabc
.Usar literais de string sem aspas produzirá um aviso para
Use of undefined constant
; mas isso não será exibido se você usar o valor padrão paraerror_reporting
(parâmetro CLI-n
).fonte
-n
sinalizador); 7.2 produz avisos; versões posteriores lançam erros!Funções de seta no PHP 7.4
O PHP 7.4 já está na versão RC2 e, esperançosamente, será lançado em cerca de 2 meses. A lista de novos recursos está aqui (esta página pode ser atualizada quando o 7.4 for lançado). Na 7.4, finalmente, o PHP possui as funções de seta; portanto, não apenas as respostas das funções podem ser mais curtas agora, mas também a passagem de fechamentos para outras funções também pode ser muito mais curta. Aqui estão alguns exemplos:
Retorno de entrada + 1:
Função anônima (fechamento) - 25 bytes - Experimente online!
Função de seta - 12 bytes - Experimente online!
Multiplique os itens da primeira entrada (matriz de entradas) pela segunda entrada (int):
Função anônima (fechamento) - 72 bytes - Experimente online!
Função de seta - 38 bytes - Experimente online!
Você percebeu que
$n
é acessível na função interna sem umause $n
declaração? Sim, esse é um dos recursos da função de seta.Como uma observação lateral, não consegui que as funções de seta funcionassem recursivamente (chame a mesma função de seta dentro de si), porque não podemos dar um nome a elas e armazená-las como um fechamento em uma variável que
$f
não se torna$f
acessível por si mesma (triste ) Portanto, este exemplo não funciona e o uso$f
na primeira linha causa um erro fatal:Mas chamar uma função de seta dentro de uma função de seta diferente funciona:
fonte
$f=fn($n)=>$n?$f($n-1):0;
você, fizer$f=$F=fn($n)=>$n?$F($n-1):0;
? Isso funcionaria? E então você liga$(5)
como de costume.Em relação à E / S do arquivo:
Link para outra pergunta relacionada , cujas respostas se encaixam aqui.
fonte
Matrizes de desreferência direta retornadas de funções.
Por exemplo, em vez disso:
Você pode fazer:
Isso funciona com métodos também:
Você também pode desreferenciar diretamente as declarações da matriz:
fonte
Use em
end()
vez dearray_pop()
A
end()
função não apenas move o ponteiro interno para o final da matriz, mas também retorna o último valor. Observe, é claro, que ele não remove esse valor; portanto, se você não se importa com o que a matriz contém posteriormente, pode usá-lo em vez dearray_pop()
.fonte
array_flip duplo vs matriz_de_ matriz vs matriz_de_ matriz
nesse caso especial, um array_flip duplo economiza 10 bytes
($f=array_flip)($k=$f($c)))
remover todos os valores double na matriz e eu ter deixado cair esta$c=[],
,|in_array($o,$c)
e substituirarray_keys($c)
com$k
Versão Online
contra
Versão online
contra array_unique, ele salva 2 bytes
Versão Online
Depois de encontrar um bug neste programa e substituição
$x[$i]==$o?:$c[$x[$i]]=$o
para($p=$x[$i])==$o?:$k[$c[$p]=$o]=$p
o duplo array_flip não era necessário mais tempofonte
array_unique
. Yay!cordas que se cruzam
Você já usou
join("DELIMITER",str_split($s))
(31 bytes) ou mesmopreg_replace(".","DELIMITER",$s)
(32 bytes)?
Existe um construtor para isso:
Tente
chunk_split($s,1,"DELIMITER")
(29 bytes).Se você omitir o terceiro parâmetro,
chunk_split
usará\r\n
; que você pode economizar 7 ou 8 bytes.Mas cuidado:
chunk_split
também anexa o delimitador à string,para que você não consiga exatamente o que deseja.
(Se você não fornecer o tamanho do pedaço, ele usará 76. Bastante incomum para o golfe com código, mas quem sabe.)
fonte
strtr
Eu amo essa ideia.unset () vs INF
Em um caso, procure um mínimo em uma matriz que você possa usar em vez de
economizar 3 bytes
fonte
str_repeat
Em alguns casos, você tem uma entrada de caracteres e deve produzi-los repetidos com uma entrada maior zero para cada caractere.
(52 bytes) é menor que
ou
(54 bytes cada)
Como funciona, por exemplo, entrada
a1b2c1
$z
não está definido (implícitoNULL
), o--$z
que não faz nada e é falso;$c="a"
,$z="1"
E$i=2
->$c.$z="a1"
é verdade -> saída"a"
--$z=0
; então definimos$c="b"
,$z="2"
(e$i=4
) ->$c.$z="b2"
é verdade -> saída"ab"
--$z=1
-> saída"abb"
--$z=0
; então definimos$c="c"
e$z=1
$c.$z="c1"
é a verdadeira saída"abbc"
--$z=0
então$c=""
e$z=""
->$c.$z=""
é falso -> quebras de loopfonte
Combinando
for
loopsSuponha que você tenha um código do seguinte formato:
isso geralmente pode ser relançado da seguinte forma:
onde
•
representa um operador combinado genérico. Isso geralmente resulta em uma redução na contagem de bytes, mas provavelmente exigirá alguma criatividade.$cond2
precisará ser escrito para que falhe na primeira vez.$post1
também deve falhar na execução pela primeira vez, embora possa ser mais fácil refatorar antecipadamente para que$post1
não esteja presente.Se você estiver trabalhando com três ou mais loops aninhados, também poderá combinar dois primeiro e depois combinar com outro, e assim por diante. Acho que geralmente tem sido mais fácil combinar de dentro para fora.
Como exemplo, considere a seguinte solução para o fractal H-carpet ( 97 bytes ):
Isso pode ser reformulado da seguinte maneira:
$e&&print
impedeprint
na primeira iteração e também não aumenta$i
.e finalmente ( 93 bytes ):
$H>$e*=3
falhará na primeira vez, pois as duas variáveis são indefinidas.fonte
Removendo caracteres em uma sequência
salva 1 caractere em comparação com
fonte
""
e, de qualquer maneira, não é muito útil.)
. Estrtr($string,[" "=>""])
é ainda mais curto.array_merge vs array_push
é um byte menor que
Não funciona da mesma forma com matrizes associativas
variável-arg-list PHP> 5.6
fonte
Use operadores booleanos em vez de
strtoupper()
estrtolower()
Se você estiver trabalhando exclusivamente com strings que consistem em caracteres do alfabeto, poderá usar operadores booleanos para alterá-los para maiúsculas ou minúsculas com menos pressionamentos de tecla do que as funções internas do PHP.
Exemplo:
As coisas são um pouco mais complicadas para cadeias de comprimento arbitrário, mas os operadores
&
e^
truncarão o resultado para o comprimento da cadeia de entrada mais curta. Assim, por exemplo, se$W
é uma sequência de espaços pelo menos tão longo como qualquer entrada$s
, então~$W&$s
é equivalente astrtoupper($s)
, e$s|$W^$s
é equivalente astrtolower($s)
(ao passo que$s|$W
, por si só irá produzir uma corda com espaços adicional, a menos$s
e$W
são de igual comprimento).fonte
utilizar funções obsoletas
Se você pode usar POSIX em vez de PERL regex sem perder mais de 5 bytes sobre a expressão, o uso
ereg
oueregi
em vez depreg_match
,split
ouspliti
em vez de preg_split.split
Também pode ser usado como sinônimo deexplode
a maioria dos delimitadores.Essas funções estão marcadas como obsoletas e lançarão
E_DEPRECATED
avisos, mas (não é possível encontrar a fonte agora) Acho que li que avisos e avisos estão ok.fonte