PHPのお勉強!

PHP TOP

extract

(PHP 4, PHP 5, PHP 7, PHP 8)

extract配列からシンボルテーブルに変数をインポートする

説明

extract(array &$array, int $flags = EXTR_OVERWRITE, string $prefix = ""): int

配列から シンボルテーブル に変数をインポートします。

各キーについて変数名として有効であるかどうか、 そして、シンボルテーブルの既存の変数と衝突しないかどうかを確認します。

警告

ユーザーの入力、例えば $_GET$_FILES のような、 信頼できないデータに 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 は、 flagsEXTR_PREFIX_SAMEEXTR_PREFIX_ALLEXTR_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.inivariables_order で定義されたものと同じ順で展開すべきであることに留意してください。

参考

  • compact() - 変数名とその値から配列を作成する
  • list() - 配列と同様の形式で、複数の変数への代入を行う

add a note

User Contributed Notes 28 notes

up
20
Michael Newton
19 years ago
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!)
up
10
FredLawl
11 years ago
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
?>
up
6
Csaba at alum dot mit dot edu
19 years ago
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.
up
10
dmikam
10 years ago
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.
up
8
Robc
13 years ago
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.
up
6
Dan O'Donnell
17 years ago
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.
up
8
CertaiN
10 years ago
[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) ""
}
}
up
2
amolocaleb at gmail dot com
6 years ago
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
up
3
phatsk+php at gmail dot com
6 years ago
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.
up
7
dotslash.lu at gmail.com
11 years ago
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
up
4
mrkhoa99 at gmail dot com
6 years ago
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
up
6