2014-10-07 2 views
2

Мне любопытно, как это работает функция PHP extract? Я хотел бы сделать слегка измененную версию. Я хочу, чтобы моя функция, чтобы имена переменных при извлечении из ключей массива из змеиного обозначения для верблюжьего например:Как extract() создает переменные в текущей области?

Теперь экстракт делает это:

$array = ['foo_bar' => 'baz']; 
extract($array); 
// $foo_bar = 'baz'; 

То, что я хотел бы это:

camelExtract($array); 
// $fooBar = 'baz'; 

Теперь я мог бы, конечно, сначала установить массив camelCase, но было бы неплохо, если бы это можно было сделать в одной функции.

редактировать:

Кажется, что некоторые люди неправильно мой вопрос. Да, я мог бы сделать это:

function camelExtract($array) 
{ 
    $array = ['foo_bar' => 'baz']; 
    $camelCased = []; 
    foreach($array as $key => $val) 
    { 
     $camelCased[camelcase($key)] = $val; 
    } 
    extract($camelCased); 
    // $fooBar = 'baz'; 


    // I can't "return" the extracted variables here 
    // .. now $fooBar is only available in this scope 
} 

camelExtract($array); 
// Not here 

Но, как я уже сказал, то $ FOOBAR видна только в пределах этой области.

Думаю, я мог бы что-то сделать как extract(camelCaseArray($array));, и это сработает.

+1

Так сделайте свою собственную функцию, чтобы сделать это –

+0

Да , но как я могу «магически» создавать переменные в текущей области действия, подобные этой функции? – Matthijn

+3

его не магия, его код –

ответ

1

extract и модификация к локальной вызываемых методов таблицы символов из функции называется магия. Невозможно выполнить эквивалент в plain-PHP без его использования.

Последняя задача может быть решена с помощью использования Джона Конде использования extraпосле, выполняющего преобразование в поставляемые ключи массива; хотя моя рекомендация заключается в том, чтобы избегать экстракционно-подобного поведения. Подход будет выглядеть примерно

extract(camelcase_keys($arr)); 

, где такой код не, завернутый в функции так, что extract выполнен из объема таблицы символов, в котором импортировать переменные.


Это extract поведение является в отличие от переменных-переменных (в вызываемой функции) и является отличие от с помощью $ GLOBALS, как он мутирует в вызываемые методы (и только в вызываемые методы) таблицы символов, как видим seen in this demo :

function extract_container() { 
    extract(array("foo" => "bar")); 
    return $foo; 
} 

echo "Extract: " . extract_container() . "\n"; // "bar" => 
echo "Current: " . $foo . "\n";     //  => {no $foo in scope} 
echo "Global: " . $GLOBALS['foo'] . "\n";  //  => {no 'foo' in GLOBALS} 

реализация C для extract можно найти в ext/standard/array.c. Такое поведение допустимо, потому что нативная функция не создает для себя новую/локальную таблицу символов PHP; как таковой, разрешено (тривиально) изменять таблицу символов вызывающего контекста PHP.

+0

Невозможно: за исключением другого ответа. – AbraCadaver

+0

Вот что я подумал, единственный, кто, на мой взгляд, понял, что вопрос изменился. Странный. – Matthijn

+0

@AbraCadaver См. Http://ideone.com/XnaEKi – user2864740

4

Это должно работать: -

function camel(array $arr) 
{ 
    foreach($arr as $a => $b) 
    { 
    $a = lcfirst(str_replace(" ", "", ucwords(str_replace("_", " ", $a)))); 
    $GLOBALS[$a] = $b; 
    } 
} 
+1

Здесь они будут доступны за пределами текущего объема. Но я не думаю, что извлечение помещает элементы в глобальную область. Эффект будет (в основном) тем же. Но теперь эти переменные «плавают», даже когда метод, который называется «верблюд», завершен. – Matthijn

+1

Если вы хотите, чтобы это было так, вы можете использовать это: - 'функция верблюд (массив $ обр) { Еогеасп ($ обр а $ а => $ б) { $ а = lcfirst (str_replace ("", "", ucwords (str_replace ("_", "", $ a)))); $ {$ a} = $ b; } } ' –

2

Вы можете (осторожно) использовать variable variables:

function camelExtract($vals = array()) { 
    foreach ($vals as $key => $v) { 
     $splitVar = explode('_', $key); 
     $first = true; 
     foreach ($splitVar as &$word) { 
      if (!$first) { 
       $word = ucfirst($word); 
      } 
      $first = false; 
     } 
     $key = implode('', $splitVar); 
     global ${$key}; 
     ${$key} = $v; 
    } 
} 

Это теперь было протестировано и функции, как и ожидалось. This condensed answer (после того, как он обратился к первому слову в нижнем регистре) также отлично работает и гораздо более сгущен - мой просто немного «шаг за шагом», чтобы работать, как делается верблюд.

+0

Аа, переменные переменные здесь кажутся возможными. Как бы вы все еще не указали, что эти переменные переменные видны только в пределах области camelExtract? Это не так, если вы используете экстракт. Это создает новые переменные в области, из которой она вызвана. Это не собственный охват. – Matthijn

+1

@Matthijn Я сделал редактирование, которое обращается к тому, что использует объявление 'global' – sjagr

+0

Это может работать действительно, но извлечение не загрязняет глобальную область действия, насколько я знаю. Но это близкое тиражирование, с глобальным загрязнением окружающей среды. – Matthijn

1
<?php 
    $arr = array('foo_bar'=>'smth'); 
    function camelExtract($arr) { 
     foreach($arr as $k=>$v) { 
      $newName = lcfirst(str_replace(" ","",ucwords(str_replace("_"," ",$k)))); 
      global $$newName; 
      $$newName = $v; 
      //var_dump($newName,$$newName); 
     } 
    } 
    camelExtract($arr); 
    ?> 

или так же, как (т то, что вы предлагаете, и лучше, чтобы имитировать оригинальный экстракт)

$camelArray[lcfirst(str_replace(" ","",ucwords(str_replace("_"," ",$k))))] = $v; 

и извлечь на результирующем camelArray

+0

Да, но здесь новые переменные доступны только в области функций camelExtract. Извлечение создает эти переменные в области, из которой она вызвана. – Matthijn

+1

Вы правы. Отредактировано для включения глобального $$ newName; – JBar