-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphp-pass-by-reference.html
More file actions
408 lines (320 loc) · 23.7 KB
/
php-pass-by-reference.html
File metadata and controls
408 lines (320 loc) · 23.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>参照渡し | SOCKET-MANAGER Framework For PHP</title>
<meta name="description" content="PHP参照渡しの詳細解説。C言語のポインタとの違い、マインクラフト連携での実装例、座標計算でのメモリ効率化など、具体的なコード例とメモリ管理の図解で分かりやすく紹介。初心者向けの基礎から実践的な使用方法まで。" />
<meta content="PHP,参照渡し,minecraft,bedrock,統合版,ソケットマネージャー" name="keywords">
<link rel="canonical" href="https://socket-manager.github.io/document/php-pass-by-reference.html" />
<script async src="https://www.googletagmanager.com/gtag/js?id=G-LF9W695NNW"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-LF9W695NNW');
</script>
<link rel="icon" href="https://socket-manager.github.io/document/favicon.ico" type="image/x-icon" />
<link type="text/css" rel="stylesheet" href="./css/common.css" media="all" />
<script src="./js/jquery-3.7.1.min.js"></script>
<script type="text/javascript" src="./js/common.js"></script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": "PHP参照渡しの使い方・実装例",
"description": "PHP参照渡しの詳細解説。C言語のポインタとの違い、マインクラフト連携での実装例、座標計算でのメモリ効率化など、具体的なコード例とメモリ管理の図解で分かりやすく紹介。初心者向けの基礎から実践的な使用方法まで。",
"keywords": "PHP, 参照渡し, アドレス渡し, ポインタ, C言語",
"articleSection": ["Technical Documentation", "PHP Programming"],
"image": "https://socket-manager.github.io/document/img/php-pass-by-reference/memory.png",
"author": {
"@type": "Person",
"name": "SOCKET-MANAGER開発チーム"
},
"publisher": {
"@type": "Organization",
"name": "SOCKET-MANAGER",
"logo": {
"@type": "ImageObject",
"url": "https://socket-manager.github.io/document/logo.png",
"width": 355,
"height": 50
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://socket-manager.github.io/document/php-pass-by-reference.html"
},
"url": "https://socket-manager.github.io/document/php-pass-by-reference.html",
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Framework Top",
"item": "https://socket-manager.github.io/document/"
},{
"@type": "ListItem",
"position": 2,
"name": "参照渡し",
"item": "https://socket-manager.github.io/document/php-pass-by-reference.html"
}]
},
"tutorial": {
"@type": "HowTo",
"name": "PHP参照渡しの実装手順",
"step": [
{
"@type": "HowToStep",
"name": "基本概念の理解",
"text": "参照渡しとアドレス渡しの違いを理解"
},
{
"@type": "HowToStep",
"name": "PHPでの実装方法",
"text": "関数定義と引数での参照渡しの使用方法"
},
{
"@type": "HowToStep",
"name": "実践的な使用例",
"text": "マインクラフトでの座標計算実装例"
}
]
},
"isPartOf": {
"@type": "WebSite",
"name": "フレームワークのご紹介",
"url": "https://socket-manager.github.io/document/"
}
}
</script>
</head>
<body>
<div class="layout">
<div class="menu" role="navigation" aria-label="ページメニュー">
<h2 class="menu-title">SOCKET-MANAGER</h2>
<h4 class="menu-reference menu-page-title-bottom"><a href="./reference/" target="_blank">>> Reference</a></h4>
<h2 class="menu-label">MAIN-MENU</h2>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./">▶フレームワークのご紹介</a></h3>
<h3 class="menu-page-title-link"><a href="./event-handler.html">▶イベントハンドラについて</a></h3>
</div>
<h3 class="menu-label-sub">IMPLEMENT</h3>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./init-class.html">▶初期化クラス</a></h3>
<h3 class="menu-page-title-link"><a href="./unit-parameter.html">▶UNITパラメータクラス</a></h3>
<h3 class="menu-page-title-link"><a href="./protocol-unit.html">▶プロトコルUNITクラス</a></h3>
<h3 class="menu-page-title-link"><a href="./command-unit.html">▶コマンドUNITクラス</a></h3>
<h3 class="menu-page-title-link"><a href="./main.html">▶メイン処理クラス</a></h3>
<h3 class="menu-page-title-link"><a href="./setting.html">▶設定ファイル</a></h3>
<h3 class="menu-page-title-link"><a href="./message.html">▶メッセージファイル</a></h3>
</div>
<div class="menu-line"></div>
<div class="menu-text">
<h3 class="menu-page-title-link-for-runtime-manager"><a href="./runtime-manager/" target="_blank">>> ランタイムライブラリ</a></h3>
<h3 class="menu-page-title-link-for-runtime-manager"><a href="./simple-socket/" target="_blank">>> シンプルソケット機能</a></h3>
</div>
<h3 class="menu-label-sub">ADVANCED</h3>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./architecture.html">▶アーキテクチャ</a></h3>
<h3 class="menu-page-title-link"><a href="./event.html">▶イベント駆動アーキテクチャ</a></h3>
<h3 class="menu-page-title-link"><a href="./ipc.html">▶IPC(プロセス間通信)</a></h3>
<h3 class="menu-page-title-link"><a href="./multi-server.html">▶マルチサーバーの構成</a></h3>
<h3 class="menu-page-title-link"><a href="./tcp-and-udp.html">▶TCP/UDP通信について</a></h3>
<h3 class="menu-page-title-link"><a href="./laravel.html">▶Laravelと連携する</a></h3>
<h3 class="menu-page-title-link"><a href="./system-setting.html">▶システム設定ファイル</a></h3>
<h3 class="menu-page-title-link"><a href="./custom-command.html">▶カスタムコマンド作成機能</a></h3>
</div>
<h3 class="menu-label-sub">OTHER-PROJECT</h3>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./new-project.html">▶新規開発環境</a></h3>
<h3 class="menu-page-title-link"><a href="./websocket.html">▶Websocketサーバー開発環境</a></h3>
<h3 class="menu-page-title-link"><a href="./dev-ops.html">▶フレームワークのDevOps環境</a></h3>
</div>
<div class="menu-line"></div>
<div class="menu-text">
<h3 class="menu-page-title-link-for-minecraft"><a href="./minecraft-contents/" target="_blank">>> マインクラフト専用環境</a></h3>
<h3 class="menu-page-title-link-for-launcher"><a href="./launcher/" target="_blank">>> GUI & CLI ランチャー</a></h3>
<h3 class="menu-page-title-link-for-rest-api"><a href="./rest-api/" target="_blank">>> REST-APIサーバー開発環境</a></h3>
</div>
<h2 class="menu-label">EXTRA-MENU</h2>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./extra-demo.html">▶デモサーバーの種類</a></h3>
<h3 class="menu-page-title-link"><a href="./extra-demo-command.html">▶デモのコマンド仕様</a></h3>
<h3 class="menu-page-title-link"><a href="./extra-demo-setting.html">▶デモの設定ファイル</a></h3>
<h3 class="menu-page-title-link"><a href="./extra-minecraft.html">▶マインクラフトの通信仕様</a></h3>
<h3 class="menu-page-title-link"><a href="./extra-close-frame.html">▶切断フレームの検証</a></h3>
</div>
<h2 class="menu-label">PHP-TECHNIQUE</h2>
<div class="menu-text">
<h3 class="menu-page-title">▼参照渡し</h3>
<ul>
<li><a href="./php-pass-by-reference.html#begin">はじめに</a></li>
</ul>
<ul>
<li><a href="./php-pass-by-reference.html#standard">お決まりの書き方</a></li>
</ul>
<ul>
<li><a href="./php-pass-by-reference.html#address">「アドレス渡し」について</a></li>
</ul>
<ul>
<li><a href="./php-pass-by-reference.html#compare">PHPとC言語との比較</a></li>
</ul>
<ul>
<li><a href="./php-pass-by-reference.html#example">実装例</a></li>
</ul>
<ul>
<li><a href="./php-pass-by-reference.html#last">おわりに</a></li>
</ul>
<h3 class="menu-page-title-link"><a href="./php-phpdoc.html">▶PHPDocのフォーマット</a></h3>
</div>
<div class="menu-dummy-for-framework"></div>
</div>
<div class="main" role="main">
<h1>【参照渡し】</h1>
<a id="begin"></a>
<h2 class="subtitle">はじめに</h2>
<div class="text-block">
ここでは当フレームワーク環境で使っているPHPの技術情報を中心に備忘録としてまとめています。<br />
今回対象となる環境は<font><a href="./minecraft-contents/index.html" target="_blank">▶マインクラフトの環境</a></font>のページでご紹介している<code>contents-project</code>というプロジェクト環境になります。<br /><br />
</div>
<a id="standard"></a>
<h2 class="subtitle">お決まりの書き方</h2>
<div class="text-block">
「参照渡し」でよく使われるのは以下のようなパターンではないでしょうか。<br />
<pre color-change="php" aria-label="引数での「参照渡し」">
function testFunction(&$test)
{
<ステートメント>
}
</pre><br />
上記のように関数呼び出しでリターン値以外のデータも取得したい時によく使われる方法だと思います。<br />
他にもクロージャーとのデータのやり取りをする場合にも使われる事がありますが、ここで注目すべきは<code>$test</code>という引数の先頭に<code>&</code>(アンパサンド)が付いているところです。<br /><br />
<font><a href="https://www.php.net/manual/ja/language.references.whatare.php" target="_blank">>> PHP公式マニュアル</a></font>には以下のように書かれています。<br />
<blockquote role="note" aria-label="PHPの公式サイトからの引用">
これは C のポインタとは異なります。
</blockquote>
ここではその「C言語のポインタ変数とどう異なるのか」に観点をおいて以下で見ていきます。<br /><br />
この書き方はC言語でもよく使われる書き方で「アドレス渡し」と呼ばれていますが、PHPは昔から他のプログラミング言語(C言語に限らず)を部分的にリスペクトしているようなところがあるので、これもその一つだと思っています。<br />
PHPとC言語ではコンパイラの処理に違いがあるので、PHP側の処理では「参照渡し」と呼ぶ事にします。<br /><br />
まずは「アドレス渡し」の考え方を理解しておいた方が分かり易いと思いますので以下をご覧ください。<br />
</div><br />
<a id="address"></a>
<h2 class="subtitle">「アドレス渡し」について</h2>
<div class="text-block">
現実世界で例えるならば、仮に東京100番地という住所に以下のイメージで山田さんの家が存在していたとします。<br /><br />
<img src="./img/php-pass-by-reference/memory.png" width="763px" loading="lazy" alt="メモリ領域の住所のイメージ" /><br /><br />
この「東京100番地」という場所がメモリ上の配置を表していて、不変的であり唯一無二のものです。(C言語ではメモリ上の配置を任意で決める事ができます)<br />
そして山田さんの家では最初3人が住んでいましたが、そのうち子供が出稼ぎに行くようになって両親の2人暮らしになったり、子供が結婚して孫とともに実家に戻ってくるなりして人数が変化していく変数だと捉える事ができます。<br /><br />
「アドレス渡し」というのはこの唯一無二の番地の部分を渡している事になるので、変数のコピーではなく変数が格納されているメモリ上の実体を常に指し示す事になります。<br /><br />
C言語ではこのアドレス(上記の例では100という値)をポインタ変数というものに代入してアドレスそのものを変数として扱う事ができますが、PHPではこのポインタ変数というものが存在しません。
<font><a href="https://www.php.net/manual/ja/language.references.whatare.php" target="_blank">>> PHP公式マニュアル</a></font>には以下のように書かれています。<br />
<blockquote role="note" aria-label="PHPの公式サイトからの引用">
リファレンスは、Unix ファイルシステムの ハードリンクのようなものであると考えられます。
</blockquote>
Unixシステムの事をご存じでない方もおられると思いますので、同じ場所を指し示すラベルのようなものだと考えてもらった方が分かり易いかもしれません。<br /><br />
</div><br />
<a id="compare"></a>
<h2 class="subtitle">PHPとC言語との比較</h2>
<div class="text-block">
以下ではPHPとC言語をソースで比較しながら見ていきます。<br />
※ソース内の黄色の部分に着目してください。<br />
<pre color-change="php" aria-label="PHPでの「参照渡し」の利用例">
$outside = null;
testFunction($outside);
printf("outside[%d]", $outside);
function testFunction(&$inside)
{
<font class="pre-yellow">$inside = 1;</font>
return;
}
</pre><br />
上記をフローで表すと以下のようになります。
<dl>
<dt>1)$outside変数に初期値としてnullを代入</dt>
<dt>2)$outside変数を「参照渡し」でtestFunction関数の引数へ渡す</dt>
<dt>3)testFunction関数内で$outside変数に1がセットされる</dt>
<dd>関数内では<code>$inside</code>変数が常に<code>$outside</code>変数(山田さんの家)の所在を示していてその<code>$outside</code>変数を参照したり代入したりできます。</dd>
<dt>4)1の値が標準出力へ出力される</dt>
</dl>
<pre color-change="php" aria-label="C言語での「アドレス渡し」の利用例">
void main(void)
{
char outside = null;
testFunction(&outside);
printf("outside[%d]", outside);
return;
}
void testFunction(char *inside)
{
<font class="pre-yellow">*inside = 1;</font>
return;
}
</pre><br />
※C言語で<code>char</code>というのは1バイトのデータ型です。<br />
※C言語で変数名の前に<code>*</code>(アスタリスク)をつけて宣言するとポインタ変数になります。また、ロジックの中でアスタリスクをつけるとそのアドレスが指し示す先のメモリ内容を参照できます。<br /><br />
上記をフローで表すと以下のようになります。
<dl>
<dt>1)outside変数に初期値としてnullを代入</dt>
<dt>2)outside変数を「アドレス渡し」でtestFunction関数の引数へ渡す</dt>
<dt>3)testFunction関数内でoutside変数に1がセットされる</dt>
<dd>関数内では<code>inside</code>変数をポインタ変数として扱っています。そして<code>*</code>(アスタリスク)を付ける事で<code>outside</code>変数(山田さんの家)の所在を示しているのでその<code>outside</code>変数を参照したり代入したりできます。</dd>
<dt>4)1の値が標準出力へ出力される</dt>
</dl><br />
<div class="menu-line"></div><br />
以上のように、処理の流れはいずれも同じですが変数の扱い方が異なっています。<br /><br />
上記のサンプルソースでは変数の値が「$inside(PHP) = *inside(C言語)」となり同じ値になりますが、C言語で「*(++inside)」と書くとカウントアップされたアドレス(101番地)が指し示す先の変数(鈴木さんの家)を参照する事になるため内容が入れ替わります。<br /><br />
PHPでの<code>$inside</code>変数は関数定義のところでC言語のように<code>&</code>(アンパサンド)を付けて渡されていますが、関数内で値を設定する時は特別な記述をしているわけでもなく、普通に1が代入されています。<br />
そしてラベルのようなもので管理されている関係で<code>testFunction</code>関数内では常に<code>$outside</code>変数を指し示す事になるので、ポインタ変数のように参照先を切り替える事ができません。<br />
</div><br />
<a id="example"></a>
<h2 class="subtitle">実装例</h2>
<div class="text-block">
それでは<font><a href="./minecraft-contents/stand.html" target="_blank">▶スタンドの弓矢</a></font>のソースから抜粋したsocket-managerフレームワーク上での実装を見てみます。<br />
今回対象にしている部分は以下の内容です。<br />
<pre color-change="php" aria-label="マインクラフトの相対座標の計算処理(app/UnitParameter/ParameterForMinecraft.php内)">
/**
* 現在の座標からヨー角を考慮した相対座標を取得
*
* @param float &$p_x X座標
* @param float &$p_y Y座標
* @param float &$p_z Z座標
* @param float $p_yrot ヨー角
* @param float $p_r 半径
*/
public function getRelativeCoordinates(float &$p_x, float &$p_y, float &$p_z, float $p_yrot, float $p_r)
{
<ステートメント>
}
</pre><br />
この<code>ParameterForMinecraft</code>クラス内で実装している<code>getRelativeCoordinates</code>というグローバルメソッドがこれに当たります。<br />
そしてこのメソッドの呼び出し側で以下のように実装しています。<br />
<pre color-change="php" aria-label="座標計算メソッドの呼び出し側の処理(app/CommandUnits/CommandForMinecraft.php内)">
// 相対座標の取得
$x = $rcv['data']['body']['player']['position']['x'];
$y = $rcv['data']['body']['player']['position']['y'];
$z = $rcv['data']['body']['player']['position']['z'];
$yrot = $rcv['data']['body']['player']['yRot'];
$p_param->getRelativeCoordinates($x, $y, $z, $yrot, 5);
// コマンド送信(座標計算の矢をスポーン)
$cmd_data = $p_param->getCommandDataForStandArrowSpawn($rcv['data']['body']['player']['name'], $x, $y, $z);
$data =
[
'data' => $cmd_data
];
$p_param->setSendStack($data);
</pre><br />
ここではあらかじめ<code>$x</code>、<code>$y</code>、<code>$z</code>変数に退避した座標を<code>getRelativeCoordinates</code>メソッドに渡して座標計算しています。<br />
XYZの座標の情報を配列等のオブジェクトとして戻り値で返す事もできますが、<code>getRelativeCoordinates</code>メソッドを通した後も<code>getCommandDataForStandArrowSpawn</code>メソッドをコールする時にXYZ座標の変数をそのまま使いたかったので「参照渡し」にしています。<br /><br />
※ここで言う「ヨー角」というのはマインクラフトワールド内での水平面の全方位を角度で表したものです。(真北が0度、真南が180度になります)<br />
</div><br />
<a id="last"></a>
<h2 class="subtitle">おわりに</h2>
<div class="text-block">
PHPマニュアルには色々書かれていますが、要はPHPでは「参照渡し」そのものをC言語のポインタ変数のように操作できないという事を謳っているだけなので、その事さえ押さえておけば特に問題になる事はないでしょう。<br />
「参照渡し」は上記で説明した以外にも使い道はありますが、それはまた別の機会でご紹介したいと思います。<br />
</div>
</div>
</div>
</body>
</html>