extract
(PHP 4, PHP 5, PHP 7, PHP 8)
extract — 配列からシンボルテーブルに変数をインポートする
パラメータ
array
-
この関数は連想配列
var_array
を引数とし、そのキーを変数名、値を変数の値として処理します。 各キー/値の組に関して、flags
およびprefix
パラメータに基づき、 現在のシンボルテーブルに変数を一つ作成します。連想配列を使用する必要があります。
EXTR_PREFIX_ALL
またはEXTR_PREFIX_INVALID
を使用しない限り、 数値添字の配列には結果は出力されません。 flags
-
無効または数値キーおよび衝突に関する対処法は、
flags
で定義されます。 これは以下の値のどれかとなります。EXTR_OVERWRITE
- 衝突があった場合、存在する変数が上書きされます。
EXTR_SKIP
- 衝突があった場合、存在する変数は上書きされません。
EXTR_PREFIX_SAME
-
衝突があった場合、
prefix
を前につけた新しい変数となります。 EXTR_PREFIX_ALL
-
全ての変数の前に
prefix
を付けます。 EXTR_PREFIX_INVALID
-
無効または数値の変数名のみに接頭辞
prefix
を付けます。 EXTR_IF_EXISTS
- 現在のシンボルテーブルに既に存在する場合にのみ上書きします。 例えば $_REQUEST からあなたが定義した変数のみを展開し 有効な変数としたいような場合に有用です。
EXTR_PREFIX_IF_EXISTS
- 同じ変数だが接頭辞をつけていないバージョンの変数が 現在のシンボルテーブルに存在する場合にのみ 変数を生成します。
EXTR_REFS
-
変数を参照として展開します。
これはインポート済みの変数が、
array
パラメータの値に常に参照付けられることを意味します。 このフラグを単独で使用するか、 あるいはflags
と和算することにより、 他のフラグとそれを組み合わせることができます。
flags
が指定されない場合、EXTR_OVERWRITE
とみなされます。 prefix
-
prefix
は、flags
がEXTR_PREFIX_SAME
、EXTR_PREFIX_ALL
、EXTR_PREFIX_INVALID
あるいはEXTR_PREFIX_IF_EXISTS
の場合にのみ必要であることに注意してください。 接頭辞を付けた変数名が有効な変数名でない場合、 この変数はシンボルテーブルにインポートされません。接頭辞は、 アンダースコア文字で配列のキーから自動的に分割されます。
戻り値
シンボルテーブルにインポートした変数の数を返します。
例
例1 extract() の例
extract の使用例としては、シンボルテーブルに wddx_deserialize() から返された連想配列を インポートすることが考えられます。
<?php
/* $var_array はwddx_deserializeから返された配列と仮定します */
$size = "large";
$var_array = array(
"color" => "blue",
"size" => "medium",
"shape" => "sphere"
);
extract($var_array, EXTR_PREFIX_SAME, "wddx");
echo "$color, $size, $shape, $wddx_size\n";
?>
上の例の出力は以下となります。
blue, large, sphere, medium
EXTR_PREFIX_SAME
を指定したため、$size
は上書きされず、$wddx_size が作成されます。
EXTR_SKIP
が指定された場合、$wddx_size は作成されません。
EXTR_OVERWRITE
の場合は、$size の値は "medium" となります。
EXTR_PREFIX_ALL
の場合は新規の変数
$wddx_color,
$wddx_size, $wddx_shape
が作成されます。
注意
extract() をユーザー入力
($_GET や $_FILES など)
のような信頼できないデータについて使用しないでください。
もし行う場合、
EXTR_SKIP
のような flags
の値が上書きされていないことを確認してください。そして
php.ini の
variables_order
で定義されたものと同じ順で展開すべきであることに留意してください。
User Contributed Notes 28 notes
They say "If the result is not a valid variable name, it is not imported into the symbol table."
What they should say is that if _any_ of the results have invalid names, _none_ of the variables get extracted.
Under 4.3.10 on Windows 2000, I was pulling some mySQL records, but needed to convert two fields into IP addresses:
<?
extract(mysql_fetch_assoc(mysql_query('SELECT * FROM foo')));
extract(mysql_fetch_assoc(mysql_query('SELECT INET_NTOA(bar) AS bar, INET_NTOA(baz) FROM foo')));
?>
I had forgotten the second AS modifier in the SQL query. Because it couldn't extract a variable called INET_NTOA(baz) into the symbol table, it didn't do either of them.
(BTW I don't normally stack functions up like that! Just to make a short example!)
It is possible to use this as a way to create public attributes for a class.
<?php
class Foo {
public function __construct ($array) {
extract($array, EXTR_REFS);
foreach ($array as $key => $value) {
$this->$key = $$key;
// Do: $this->key = $key; if $key is not a string.
}
}
}
$array = array(
'valueOne' => 'Test Value 1',
'valueTwo' => 'Test Value 2',
'valueThree' => 'Test Value 3'
);
$foo = new Foo($array);
// Works
echo $foo->valueOne; // Test Value 1
echo $foo->valueTwo; // Test Value 2
// Does not work!
echo $foo::$valueOne; // Fatal error: Access to undeclared static property: Test::$valueOne
?>
Sometimes you may want to extract only a named subset of the key/value pairs in an array. This keeps things more orderly and could prevent an unrelated variable from getting clobbered from an errant key. For example,
$things = 'unsaid';
$REQUEST = array(He=>This, said=>1, my=>is, info=>2, had=>a,
very=>3, important=>test, things=>4);
$aVarToExtract = array(my, important, info);
extract (array_intersect_key ($REQUEST, array_flip($aVarToExtract)));
will extract
$my = 'is';
$important = 'test';
$info = 2;
but will leave certain
$things = 'unsaid'
Csaba Gabor from Vienna
NB. Of course the composite request coming in from a web page is in $_REQUEST.
I have made some tests to compare the speed of next constructions:
<?php
extract($ARRAY);
// vs.
foreach($ARRAY as $key=>$value)
$$key = $value;
?>
Surprisingly for me extract is 20%-80% slower then foreach construction. I don't really understand why, but it's so.
When extracting from a row after a database query using for example:
$row = mysql_fetch_array($result, MYSQL_ASSOC)
extract($row);
I find that the resultant variables may not match the variable type in the database. In particular I have found integers in the database may gettype() to string on the extracted variable.
Following up on ktwombley at gmail dot com's post:
Presumably one easy way of dealing with this security issue is to use the EXTR_IF_EXISTS flag and make sure
a) your define acceptable input variables beforehand (i.e. as empty variables)
b) Sanitise any user input to avoid unacceptable variable content.
If you do these two things, then I'm not sure I see the difference between extract($_REQUEST,EXTR_IF_EXISTS); and assigning each of the variables by hand.
I'm not talking here about the idea of storing the variables in a database, just the immediately necessary steps to allow you to use extract on REQUEST arrays with relative safety.
[New Version]
Example Usage:
<?php
$_GET['A']['a'] = ' CORRECT(including some spaces) ';
$_GET['A']['b'] = ' CORRECT(including some spaces) ';
$_GET['A']['c'] = "Invalid UTF-8 sequence: \xe3\xe3\xe3";
$_GET['A']['d']['invalid_structure'] = 'INVALID';
$_GET['B']['a'] = ' CORRECT(including some spaces) ';
$_GET['B']['b'] = "Invalid UTF-8 sequence: \xe3\xe3\xe3";
$_GET['B']['c']['invalid_structure'] = 'INVALID';
$_GET['B']["Invalid UTF-8 sequence: \xe3\xe3\xe3"] = 'INVALID';
$_GET['C']['a'] = ' CORRECT(including some spaces) ';
$_GET['C']['b'] = "Invalid UTF-8 sequence: \xe3\xe3\xe3";
$_GET['C']['c']['invalid_structure'] = 'INVALID';
$_GET['C']["Invalid UTF-8 sequence: \xe3\xe3\xe3"] = 'INVALID';
$_GET['unneeded_item'] = 'UNNEEDED';
var_dump(filter_struct_utf8(INPUT_GET, array(
'A' => array(
'a' => '',
'b' => FILTER_STRUCT_TRIM,
'c' => '',
'd' => '',
),
'B' => FILTER_STRUCT_FORCE_ARRAY,
'C' => FILTER_STRUCT_FORCE_ARRAY | FILTER_STRUCT_TRIM,
)));
?>
Example Result:
array(3) {
["A"]=>
array(4) {
["a"]=>
string(36) " CORRECT(including some spaces) "
["b"]=>
string(30) "CORRECT(including some spaces)"
["c"]=>
string(0) ""
["d"]=>
string(0) ""
}
["B"]=>
array(3) {
["a"]=>
string(36) " CORRECT(including some spaces) "
["b"]=>
string(0) ""
["c"]=>
string(0) ""
}
["C"]=>
array(3) {
["a"]=>
string(30) "CORRECT(including some spaces)"
["b"]=>
string(0) ""
["c"]=>
string(0) ""
}
}
If an object is typecasted into an array and "extracted",only the public properties will be accessible.Methods are of course omitted.
<?php
class Test{
public $name = '';
protected $age = 10;
public $status = 'disabled';
private $isTrue = false;
public function __construct()
{
$this->name = 'Amolo';
$this->status = 'active';
}
public function getName()
{
return $this->name;
}
public function getAge()
{
return $this->age;
}
public function getStatus()
{
return $this->status;
}
}
$obj = (array) new Test();
var_dump($obj);
/* array(4) { ["name"]=> string(5) "Amolo" ["*age"]=> int(10) ["status"]=> string(6) "active" ["TestisTrue"]=> bool(false) } */
extract((array)new Test());
echo $name; //Amolo
echo $status; //active
echo $age;//Notice: Undefined variable: age
echo $isTrue;//Notice: Undefined variable: isTrue
Using extract's return parameter can lead to unintended results, particularly with EXTR_REFS:
<?php
$my_data = [
'count' => 15,
'name' => 'foo',
];
$count = extract( $my_data, EXTR_REFS );
echo $my_data['count']; // 2, not 15.
You can't extract a numeric indexed array(e.g. non-assoc array).
<?php
$a = array(
1,
2
);
extract($a);
var_dump(${1});
?>
result:
PHP Notice: Undefined variable: 1 in /Users/Lutashi/t.php on line 7
Notice: Undefined variable: 1 in /Users/Lutashi/t.php on line 7
NULL
We can use extract () function for Template Engine:
<?php
#Template.php
class Template
{
protected $viewVars;
public function renderPage($tpl)
{
ob_start();
extract($this->viewVars, EXTR_SKIP);
include $tpl;
return ob_end_flush();
}
public function assign($arr)
{
foreach ($arr as $key => $value) {
$this->viewVars[$key] = $value;
}
return $this;
}
}
$template = new Template();
$template->assign(
[ 'pageHeader' => 'Page Header', 'content' => 'This is the content page']
);
$template->renderPage('tpl.php');
#tpl.php
<h1><?= $pageHeader; ?></h1>
<p><?= $content ;?></p>
Output:
Page Header
This is the content page