aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Dockerfile13
-rw-r--r--Makefile26
-rw-r--r--note.md465
-rw-r--r--quiz.php81
-rw-r--r--slide.pdfbin0 -> 291947 bytes
-rw-r--r--slide.saty1437
7 files changed, 2023 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2d5cb5e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.satysfi-aux
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..1ec2f3c
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,13 @@
+FROM amutake/satysfi
+
+RUN opam update && \
+ opam install satysfi-base
+
+RUN opam install satysfi-class-slydifi && \
+ opam install satysfi-fonts-noto-sans && \
+ opam install satysfi-fonts-noto-sans-cjk-jp
+
+RUN eval $(opam env) && \
+ satyrographos install
+
+WORKDIR /work
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9df8a46
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+.PHONY: all
+all:
+ docker run \
+ --rm \
+ --name sandbox-satysfi \
+ --mount type=bind,src=$$(pwd),dst=/work \
+ sandbox-satysfi \
+ satysfi /work/slide.saty
+
+.PHONY: shell
+shell:
+ docker run \
+ -it \
+ --rm \
+ --name sandbox-satysfi \
+ --mount type=bind,src=$$(pwd),dst=/work \
+ sandbox-satysfi \
+ sh
+
+.PHONY: build
+build:
+ docker build --tag sandbox-satysfi .
+
+.PHONY: clean
+clean:
+ rm -f *.pdf *.satysfi-aux
diff --git a/note.md b/note.md
new file mode 100644
index 0000000..00846c9
--- /dev/null
+++ b/note.md
@@ -0,0 +1,465 @@
+https://www.php.net/manual/ja/language.references.whatdo.php
+https://www.phpinternalsbook.com/
+
+
+
+```c
+ZEND_VM_HANDLER(30, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC)
+{
+ USE_OPLINE
+ zval *variable_ptr;
+ zval *value_ptr;
+
+ SAVE_OPLINE();
+ value_ptr = GET_OP2_ZVAL_PTR_PTR(BP_VAR_W);
+ variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
+
+ if (OP1_TYPE == IS_VAR &&
+ UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) {
+
+ zend_throw_error(NULL, "Cannot assign by reference to an array dimension of an object");
+ variable_ptr = &EG(uninitialized_zval);
+ } else if (OP2_TYPE == IS_VAR &&
+ opline->extended_value == ZEND_RETURNS_FUNCTION &&
+ UNEXPECTED(!Z_ISREF_P(value_ptr))) {
+
+ variable_ptr = zend_wrong_assign_to_variable_reference(
+ variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC);
+ } else {
+ // !!!
+ zend_assign_to_variable_reference(variable_ptr, value_ptr);
+ }
+
+ if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
+ ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr);
+ }
+
+ FREE_OP2();
+ FREE_OP1();
+ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+}
+
+// https://github.com/php/php-src/blob/php-8.2.3/Zend/zend_execute.c#L533-L557
+static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr)
+{
+ zend_reference *ref;
+
+ if (EXPECTED(!Z_ISREF_P(value_ptr))) {
+ ZVAL_NEW_REF(value_ptr, value_ptr);
+ } else if (UNEXPECTED(variable_ptr == value_ptr)) {
+ return;
+ }
+
+ ref = Z_REF_P(value_ptr);
+ GC_ADDREF(ref);
+ if (Z_REFCOUNTED_P(variable_ptr)) {
+ zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
+
+ if (GC_DELREF(garbage) == 0) {
+ ZVAL_REF(variable_ptr, ref);
+ rc_dtor_func(garbage);
+ return;
+ } else {
+ gc_check_possible_root(garbage);
+ }
+ }
+ ZVAL_REF(variable_ptr, ref);
+}
+
+// https://github.com/php/php-src/blob/php-8.2.3/Zend/zend_types.h#L1077-L1086
+#define ZVAL_NEW_REF(z, r) do { \
+ zend_reference *_ref = \
+ (zend_reference *) emalloc(sizeof(zend_reference)); \
+ GC_SET_REFCOUNT(_ref, 1); \
+ GC_TYPE_INFO(_ref) = GC_REFERENCE; \
+ ZVAL_COPY_VALUE(&_ref->val, r); \
+ _ref->sources.ptr = NULL; \
+ Z_REF_P(z) = _ref; \
+ Z_TYPE_INFO_P(z) = IS_REFERENCE_EX; \
+ } while (0)
+
+ zend_reference *_ref = (zend_reference *)malloc(/* 略 */);
+ _ref->refcount = 1;
+ ZVAL_COPY_VALUE(&_ref->val, value_ptr);
+ value_ptr->value.ref = _ref;
+ value_ptr->type_info = IS_REFERENCE;
+
+#define GC_SET_REFCOUNT(p, rc) zend_gc_set_refcount(&(p)->gc, rc)
+static zend_always_inline uint32_t zend_gc_set_refcount(zend_refcounted_h *p, uint32_t rc) {
+ p->refcount = rc;
+ return p->refcount;
+}
+#define GC_TYPE_INFO(p) (p)->gc.u.type_info
+
+ do { \
+ zval *_z1 = (z); \
+ const zval *_z2 = (v); \
+ zend_refcounted *_gc = Z_COUNTED_P(_z2); \
+ uint32_t _t = Z_TYPE_INFO_P(_z2); \
+ ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t); \
+ } while (0)
+
+#define Z_TYPE_INFO(zval) (zval).u1.type_info
+#define Z_TYPE_INFO_P(zval_p) Z_TYPE_INFO(*(zval_p))
+
+#define Z_REF_P(zval_p) Z_REF(*(zval_p))
+#define Z_REF(zval) (zval).value.ref
+
+#define ZVAL_REF(z, r) do { \
+ zval *__z = (z); \
+ Z_REF_P(__z) = (r); \
+ Z_TYPE_INFO_P(__z) = IS_REFERENCE_EX; \
+ } while (0)
+
+#define GC_ADDREF(p) zend_gc_addref(&(p)->gc)
+
+static zend_always_inline uint32_t zend_gc_addref(zend_refcounted_h *p) {
+ ZEND_RC_MOD_CHECK(p);
+ return ++(p->refcount);
+}
+```
+
+
+
+
+
+
+
+# php-src
+
+```c
+typedef struct _zval_struct zval;
+
+// https://github.com/php/php-src/blob/php-8.2.3/Zend/zend_types.h#L315-L340
+struct _zval_struct {
+ zend_value value; /* value */
+ union {
+ uint32_t type_info;
+ struct {
+ ZEND_ENDIAN_LOHI_3(
+ zend_uchar type, /* active type */
+ zend_uchar type_flags,
+ union {
+ uint16_t extra; /* not further specified */
+ } u)
+ } v;
+ } u1;
+ union {
+ uint32_t next; /* hash collision chain */
+ uint32_t cache_slot; /* cache slot (for RECV_INIT) */
+ uint32_t opline_num; /* opline number (for FAST_CALL) */
+ uint32_t lineno; /* line number (for ast nodes) */
+ uint32_t num_args; /* arguments number for EX(This) */
+ uint32_t fe_pos; /* foreach position */
+ uint32_t fe_iter_idx; /* foreach iterator index */
+ uint32_t property_guard; /* single property guard */
+ uint32_t constant_flags; /* constant flags */
+ uint32_t extra; /* not further specified */
+ } u2;
+};
+
+// https://github.com/php/php-src/blob/php-8.2.3/Zend/zend_types.h#L295-L313
+typedef union _zend_value {
+ zend_long lval; /* long value */
+ double dval; /* double value */
+ zend_refcounted *counted;
+ zend_string *str;
+ zend_array *arr;
+ zend_object *obj;
+ zend_resource *res;
+ zend_reference *ref;
+ zend_ast_ref *ast;
+ zval *zv;
+ void *ptr;
+ zend_class_entry *ce;
+ zend_function *func;
+ struct {
+ uint32_t w1;
+ uint32_t w2;
+ } ww;
+} zend_value;
+
+// https://github.com/php/php-src/blob/php-8.2.3/Zend/zend_types.h#L548-L560
+/* Regular data types: Must be in sync with zend_variables.c. */
+#define IS_UNDEF 0
+#define IS_NULL 1
+#define IS_FALSE 2
+#define IS_TRUE 3
+#define IS_LONG 4
+#define IS_DOUBLE 5
+#define IS_STRING 6
+#define IS_ARRAY 7
+#define IS_OBJECT 8
+#define IS_RESOURCE 9
+#define IS_REFERENCE 10
+#define IS_CONSTANT_AST 11 /* Constant expressions */
+
+// https://github.com/php/php-src/blob/php-8.2.3/Zend/zend_types.h#L537-L541
+struct _zend_reference {
+ zend_refcounted_h gc;
+ zval val;
+ zend_property_info_source_list sources;
+};
+
+typedef struct _zend_refcounted_h {
+ uint32_t refcount; /* reference counter 32-bit */
+ union {
+ uint32_t type_info;
+ } u;
+} zend_refcounted_h;
+```
+
+
+
+
+# PHP Manual
+
+
+https://www.php.net/manual/en/language.references.whatdo.php
+
+
+```php
+<?php
+
+$a =& $b;
+```
+
+> $a and $b are completely equal here. $a is not pointing to $b or vice versa. $a and $b are pointing to the same place.
+
+> If you assign, pass, or return an undefined variable by reference, it will get created.
+
+```php
+<?php
+
+function foo(&$var) {}
+
+foo($a);
+$b = [];
+foo($b['b']);
+// array_key_exists('b', $b) // => true
+
+$c = new stdClass();
+foo($c->d);
+// property_exists($c, 'd') // => true
+```
+
+```php
+<?php
+
+function& foo() {}
+
+$a =& foo();
+
+$b =& new stdClass();
+// => Error!
+```
+
+> If you assign a reference to a variable declared global inside a function,
+> the reference will be visible only inside the function. You can avoid this by
+> using the `$GLOBALS` array.
+
+
+
+!!!
+
+```php
+<?php
+
+$var1 = "Example variable";
+$var2 = "";
+
+function global_references($use_globals) {
+ global $var1, $var2;
+ if ($use_globals) {
+ $GLOBALS["var2"] =& $var1; // visible also in global context
+ } else {
+ $var2 =& $var1; // visible only inside the function
+ }
+}
+
+global_references(false);
+echo "var2 is set to '$var2'\n"; // var2 is set to ''
+global_references(true);
+echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable'
+```
+
+> Think about `global $var;` as a shortcut to `$var =& $GLOBALS['var'];`. Thus
+> assigning another reference to `$var` only changes the local variable's
+> reference.
+
+
+
+
+> If you assign a value to a variable with references in a foreach statement,
+> the references are modified too.
+
+```php
+<?php
+
+$ref = 0;
+$row =& $ref;
+
+foreach ([1, 2, 3] as $row) {
+ // do something
+}
+echo $ref; // 3: last element of the iterated array
+```
+
+
+!!!
+
+> While not being strictly an assignment by reference, expressions created with
+> the language construct `array()` can also behave as such by prefixing `&` to the
+> array element to add. Example:
+
+```php
+<?php
+
+$a = 1;
+$b = [2, 3];
+$arr = [&$a, &$b[0], &$b[1]];
+$arr[0]++; $arr[1]++; $arr[2]++;
+var_dump($a);
+// => 2
+var_dump($b);
+// => [3, 4]
+```
+
+
+!!!
+
+> Note, however, that references inside arrays are potentially dangerous. Doing
+> a normal (not by reference) assignment with a reference on the right side
+> does not turn the left side into a reference, but references inside arrays
+> are preserved in these normal assignments. This also applies to function
+> calls where the array is passed by value. Example:
+
+```php
+<?php
+
+/* Assignment of scalar variables */
+$a = 1;
+$b =& $a;
+$c = $b;
+$c = 7; //$c is not a reference; no change to $a or $b
+
+/* Assignment of array variables */
+$arr = [1, 2];
+$a =& $arr[0]; //$a and $arr[0] are in the same reference set
+$arr2 = $arr; //not an assignment-by-reference!
+$arr2[0]++;
+$arr2[1]++;
+/* $a == 2, $arr == [2, 2] */
+/* The contents of $arr are changed even though it's not a reference! */
+```
+
+> In other words, the reference behavior of arrays is defined in an
+> element-by-element basis; the reference behavior of individual elements is
+> dissociated from the reference status of the array container.
+
+
+
+!!!
+
+https://www.php.net/manual/en/language.references.arent.php
+
+```php
+<?php
+
+function foo(&$var) {
+ $var =& $GLOBALS["baz"];
+}
+foo($bar);
+```
+
+
+https://www.php.net/manual/en/language.references.pass.php
+
+
+リファレンス渡しできるもの
+
+* 変数
+* リファレンス返しする関数の返り値
+
+```php
+<?php
+
+$a = 1;
+$b =& $a;
+unset($a);
+```
+
+https://www.php.net/manual/en/language.references.spot.php
+
+Reference っぽくない reference
+
+```php
+<?php
+
+// global $var;
+$var =& $GLOBALS["var"];
+```
+
+
+
+
+# PHP Internals Book
+
+https://www.phpinternalsbook.com/
+
+## https://www.phpinternalsbook.com/php7/zvals/basic_structure.html
+
+> The IS_REFERENCE type in conjunction with the zend_reference *ref member is
+> used to represent a PHP reference. While from a userland perspective
+> references are not a separate type, internally references are represented as
+> a wrapper around another zval, that can be shared by multiple places.
+
+
+## https://www.phpinternalsbook.com/php7/zvals/references.html
+
+> People will commonly say that “$b is a reference to $a”. However, this is not
+> quite correct, in that references in PHP have no concept of directionality.
+> After $b =& $a, both $a and $b reference a common value, and neither of the
+> variables is privileged in any way.
+
+-----
+
+> Normally, PHP does not track who or what makes use of a given reference. The
+> only knowledge that is stored is how many users there are (through the
+> refcount), so that the reference may be destroyed in time.
+
+> However, due to the introduction of typed properties in PHP 7.4, we do need
+> to track of which typed properties make use of a certain reference, in order
+> to enforce property types for indirect modifications through references:
+
+```php
+<?php
+
+class Test {
+ public int $prop = 42;
+}
+$test = new Test();
+$ref =& $test->prop;
+$ref = "string"; // TypeError
+```
+
+> The sources member of zend_reference stores a list of zend_property_info
+> pointers to track typed properties that use the reference. Macros like
+> ZEND_REF_HAS_TYPE_SOURCES(), ZEND_REF_ADD_TYPE_SOURCE(), and
+> ZEND_REF_DEL_TYPE_SOURCE()
+
+
+
+
+# プロポーザル
+
+https://fortee.jp/phperkaigi-2023/proposal/95e4dd94-5fc7-40fe-9e1a-230e36404cbe
+
+## 詳説「参照」:PHP 処理系の実装から参照を理解する
+
+> PHP における参照に似た機能は、他の言語にも存在しています。C のポインタ、C++ の参照、Java の参照型、C# の参照渡し……。しかしこれらは、それぞれ細かな点で PHP のそれとは異なっています。
+> PHP における参照を完全に理解すべく、1) PHP レベルでの挙動を観察し、2) PHP 処理系 (https://github.com/php/php-src) のソースコードを追いかけます。
+>
+> 対象: 重箱の隅をつつきたい PHPer、または PHP の language lawyer になりたい人。PHP 処理系は C で書かれていますが、C の知識は (あまり) 要求しないようにするつもりです
+> 目標: PHP の参照を、実装レベルで完全に理解すること、また、php-src を少しだけ探索できるようになること
+> 話さないこと: 参照のメリット・デメリットや使うべき場面
diff --git a/quiz.php b/quiz.php
new file mode 100644
index 0000000..f68e766
--- /dev/null
+++ b/quiz.php
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+####################################
+# Q1
+
+$x = 1;
+$y =& $x;
+$y = 2;
+echo "x = $x", PHP_EOL;
+// => 2
+echo "y = $y", PHP_EOL;
+// => 2
+
+####################################
+# Q2
+
+$x = 1;
+$y =& $x;
+$z = $y;
+$z = 2;
+echo "x = $x", PHP_EOL;
+// => 1
+echo "y = $y", PHP_EOL;
+// => 1
+echo "z = $z", PHP_EOL;
+// => 2
+
+####################################
+# Q3
+
+$xs = [1, 2];
+$x =& $xs[0];
+$x = 42;
+echo "x = $x", PHP_EOL;
+// => 42
+echo "xs = [$xs[0], $xs[1]]", PHP_EOL;
+// => [42, 2]
+
+####################################
+# Q4
+
+$xs = [1, 2];
+$x =& $xs[0];
+$ys = $xs;
+$x = 42;
+$ys[1] = 3;
+echo "x = $x", PHP_EOL;
+// => 42
+echo "xs = [$xs[0], $xs[1]]", PHP_EOL;
+// => [42, 2]
+echo "ys = [$ys[0], $ys[1]]", PHP_EOL;
+// => [42, 3]
+
+####################################
+# Q5 (割愛)
+
+$g = 1;
+function f(&$x) {
+ $x =& $GLOBALS['g'];
+}
+$y = 0;
+f($y);
+$y = 42;
+echo "y = $y", PHP_EOL;
+// => 42
+echo "g = $g", PHP_EOL;
+// => 1
+
+####################################
+# Q6 (割愛)
+
+class C {
+ public int $x = 1;
+}
+$c = new C();
+$y =& $c->x;
+$y = 'PHPerKaigi';
+// => Fatal error: TypeError
+// Cannot assign string to reference held by property C::$x of type int
diff --git a/slide.pdf b/slide.pdf
new file mode 100644
index 0000000..0129e23
--- /dev/null
+++ b/slide.pdf
Binary files differ
diff --git a/slide.saty b/slide.saty
new file mode 100644
index 0000000..9cc0a19
--- /dev/null
+++ b/slide.saty
@@ -0,0 +1,1437 @@
+% {{{1 Header
+
+@require: class-slydifi/theme/akasaka
+@require: code-printer/code-design
+@require: code-printer/code-printer
+@require: code-printer/code-syntax
+@require: code-printer/code-theme
+@require: enumitem/enumitem
+@require: figbox/figbox
+
+% {{{1 Preamble
+
+% {{{2 Utilities
+
+let github-link-to-file repo ref file =
+ `https://github.com/` ^ repo ^ `/blob/` ^ ref ^ `/` ^ file
+
+% {{{2 Constants
+
+let php-src-version = `php-8.2.3`
+
+% {{{3 Quizzes
+
+% {{{4 Q1
+
+let quiz-1-q = `$x = 1;
+$y =& $x;
+$y = 42;
+echo "x = $x\n";
+// => ???
+echo "y = $y\n";
+// => ???
+
+`#
+
+let quiz-1-a = `$x = 1;
+$y =& $x;
+$y = 42;
+echo "x = $x\n";
+// => 42
+echo "y = $y\n";
+// => 42
+
+`#
+
+% {{{4 Q2
+
+let quiz-2-q = `$x = 1;
+$y =& $x;
+$z = $y;
+$z = 42;
+echo "x = $x\n";
+// => ???
+echo "y = $y\n";
+// => ???
+echo "z = $z\n";
+// => ???
+
+`#
+
+let quiz-2-a = `$x = 1;
+$y =& $x;
+$z = $y;
+$z = 42;
+echo "x = $x\n";
+// => 1
+echo "y = $y\n";
+// => 1
+echo "z = $z\n";
+// => 42
+
+`#
+
+% {{{4 Q3
+
+let quiz-3-q = `$xs = [1, 2];
+$x =& $xs[0];
+$x = 42;
+echo "x = $x\n";
+// => ???
+echo "xs = [$xs[0], $xs[1]]\n";
+// => [???, ???]
+
+`#
+
+let quiz-3-a = `$xs = [1, 2];
+$x =& $xs[0];
+$x = 42;
+echo "x = $x\n";
+// => 42
+echo "xs = [$xs[0], $xs[1]]\n";
+// => [42, 2]
+
+`#
+
+% {{{4 Q4
+
+let quiz-4-q = `$xs = [1, 2];
+$x =& $xs[0];
+$ys = $xs;
+$x = 42;
+$ys[1] = 3;
+echo "x = $x\n";
+// => ???
+echo "xs = [$xs[0], $xs[1]]\n";
+// => [???, ???]
+echo "ys = [$ys[0], $ys[1]]\n";
+// => [???, ???]
+
+`#
+
+let quiz-4-a = `$xs = [1, 2];
+$x =& $xs[0];
+$ys = $xs;
+$x = 42;
+$ys[1] = 3;
+echo "x = $x\n";
+// => 42
+echo "xs = [$xs[0], $xs[1]]\n";
+// => [42, 2]
+echo "ys = [$ys[0], $ys[1]]\n";
+// => [42, 3]
+
+`#
+
+% {{{4 Q5
+
+let quiz-5-q = `$g = 1;
+function f(&$x) {
+ $x =& $GLOBALS['g'];
+}
+$y = 0;
+f($y);
+$y = 42;
+echo "y = $y", PHP_EOL;
+// => ???
+echo "g = $g", PHP_EOL;
+// => ???
+
+`#
+
+let quiz-5-a = `$g = 1;
+function f(&$x) {
+ $x =& $GLOBALS['g'];
+}
+$y = 0;
+f($y);
+$y = 42;
+echo "y = $y", PHP_EOL;
+// => 42
+echo "g = $g", PHP_EOL;
+// => 1
+
+`#
+
+% {{{4 Q6
+
+let quiz-6-q = `class C {
+ public int $x = 1;
+}
+$c = new C();
+$y =& $c->x;
+$y = 'PHPerKaigi';
+// => ???
+
+`#
+
+let quiz-6-a = `class C {
+ public int $x = 1;
+}
+$c = new C();
+$y =& $c->x;
+$y = 'PHPerKaigi';
+// => Fatal error: TypeError
+
+`#
+
+% {{{3 php/php-src
+
+let zval-def = `struct zval {
+ zend_value value; /* 値本体 */
+ uint32_t type_info; /* 型情報 */
+
+ union {
+ /* その他メタデータ (省略) */
+ } u2;
+};
+
+`#
+
+let zend-value-def = `union zend_value {
+ zend_long lval; /* 整数 */
+ double dval; /* 浮動小数点数 */
+ zend_string *str; /* 文字列 */
+ zend_array *arr; /* 配列 */
+ zend_object *obj; /* オブジェクト */
+ zend_resource *res; /* リソース */
+ zend_reference *ref; /* 参照 */
+ /* (略) */
+};
+
+`#
+
+let zval-types = `#define IS_UNDEF 0 /* 不明、未初期化 */
+#define IS_NULL 1 /* null */
+#define IS_FALSE 2 /* false */
+#define IS_TRUE 3 /* true */
+#define IS_LONG 4 /* 整数 */
+#define IS_DOUBLE 5 /* 浮動小数点数 */
+#define IS_STRING 6 /* 文字列 */
+#define IS_ARRAY 7 /* 配列 */
+#define IS_OBJECT 8 /* オブジェクト */
+#define IS_RESOURCE 9 /* リソース */
+#define IS_REFERENCE 10 /* 参照 */
+
+`#
+
+let zend-reference-def = `struct zend_reference {
+ uint32_t refcount; /* 参照カウント */
+ uint32_t type_info; /* (説明略) */
+ zval val; /* 指している値 */
+ zend_property_info_source_list sources; /* (説明略) */
+};
+
+`#
+
+let zend-assign-to-variable-reference-def = `void zend_assign_to_variable_reference(
+ zval *lhs, zval *rhs
+) {
+ ZVAL_NEW_REF(rhs);
+
+ rhs->value->refcount++;
+
+ lhs->value = rhs->value;
+ lhs->type_info = IS_REFERENCE;
+}
+
+`#
+
+let zend-assign-to-variable-reference-simple = `ZVAL_NEW_REF(rhs);
+
+rhs->value->refcount++;
+
+lhs->value = rhs->value;
+lhs->type_info = IS_REFERENCE;
+
+`#
+
+let zval-new-ref-def = `ZVAL_NEW_REF(z)
+ zend_reference *ref = new zend_reference();
+ ref->refcount = 1;
+ /* z の中に入っている値を ref にコピー */
+ ZVAL_COPY_VALUE(&ref->val, z);
+ z->value = ref;
+ z->type_info = IS_REFERENCE;
+
+`#
+
+let zval-new-ref-simple = `/* ZVAL_NEW_REF */
+zend_reference *ref =
+ new zend_reference();
+ref->refcount = 1;
+ZVAL_COPY_VALUE(&ref->val, rhs);
+rhs->value = ref;
+rhs->type_info = IS_REFERENCE;
+
+`#
+
+% {{{2 Blocks
+
+let-block +code-block-php source =
+ '<
+ +code-printer?:(
+ CodePrinter.make-config CodeSyntax.php CodeTheme.iceberg-light
+ |> CodePrinter.set-number-fun CodeDesign.number-fun-null
+ )(source);
+ >
+
+let-block +code-block-c source =
+ '<
+ +code-printer?:(
+ CodePrinter.make-config CodeSyntax.c CodeTheme.iceberg-light
+ |> CodePrinter.set-number-fun CodeDesign.number-fun-null
+ )(source);
+ >
+
+let-block +fig-arrow from to =
+ let (to-x, to-y) = to in
+ '<
+ +fig-abs-pos(to)(FigBox.from-bbox-graphics [
+ Gr.line from to |> stroke 3pt Color.black;
+ Gr.polygon to [
+ (to-x -' 2.5pt, to-y +' 4.33pt);
+ (to-x +' 2.5pt, to-y +' 4.33pt);
+ ] |> stroke 3pt Color.black;
+ ]);
+ >
+
+% {{{2 Inlines
+
+let-inline \php-src-link file line-from line-to =
+ let file-with-line = file ^ `#L` ^ arabic line-from ^ `-L` ^ arabic line-to in
+ let url = github-link-to-file `php/php-src` php-src-version file-with-line in
+ {\link?:(embed-string file-with-line)(url);}
+
+% }}}
+open FigBox
+
+in
+
+% {{{1 Body
+
+document '<
+ +make-title(|
+ title = {
+ |詳説「参照」
+ |PHP の参照を完全に理解する
+ |};
+ author = {|nsfisis (いまむら)|};
+ date = {|PHPerKaigi 2023|};
+ |);
+
+ +frame{自己紹介}<
+ +p{
+ nsfisis (いまむら)
+ }
+ +p{
+ \@ デジタルサーカス株式会社
+ }
+ >
+
+ +frame{アジェンダ}<
+ +enumerate{
+ * 参照の不思議クイズ
+ * PHP処理系のソースを読む
+ ** zvalとzend_reference
+ ** 参照代入
+ * クイズの解説
+ * まとめ
+ }
+ >
+
+ +section{|参照の不思議クイズ|}<
+ +frame{参照の不思議クイズ: Q1}<
+ +code-block-php(quiz-1-q);
+ >
+
+ +frame{参照の不思議クイズ: Q1}<
+ +code-block-php(quiz-1-a);
+ >
+
+ +frame{参照の不思議クイズ: Q2}<
+ +code-block-php(quiz-2-q);
+ >
+
+ +frame{参照の不思議クイズ: Q2}<
+ +code-block-php(quiz-2-a);
+ >
+
+ +frame{参照の不思議クイズ: Q3}<
+ +code-block-php(quiz-3-q);
+ >
+
+ +frame{参照の不思議クイズ: Q3}<
+ +code-block-php(quiz-3-a);
+ >
+
+ +frame{参照の不思議クイズ: Q4}<
+ +code-block-php(quiz-4-q);
+ >
+
+ +frame{参照の不思議クイズ: Q4}<
+ +code-block-php(quiz-4-a);
+ >
+ >
+
+ +section{|PHP処理系のソースを読む|}<
+ +frame{はじめに}<
+ +listing{
+ * PHP v8.2.3 (\link?:({GitHub})(`https://github.com/php/php-src/tree/php-8.2.3`);)
+ * ソースコードは発表向けに改変しています
+ * C言語としては不正確な説明を話したり載せたりすることがあります
+ }
+ >
+
+ +section{|zvalとzend_reference|}<
+ +frame{zvalとは}<
+ +p{
+ PHPの「値」全般
+ \listing{
+ * 整数 (\inline-code(`0`);、\inline-code(`42`);、\inline-code(`57`);)
+ * 浮動小数点数 (\inline-code(`3.14159265`);)
+ * 文字列 (\inline-code(`"Hello, World!"`);)
+ * 配列 (\inline-code(`[1, 2, 3]`);)
+ * クラス (\inline-code(`new \Exception`);)
+ }
+ など
+ }
+ >
+
+ +frame{zvalの定義}<
+ +code-block-c(zval-def);
+ +p{
+ \php-src-link(`Zend/zend_types.h`)(315)(340);
+ }
+ >
+
+ +frame{zend_valueの定義}<
+ +code-block-c(zend-value-def);
+ +p{
+ \php-src-link(`Zend/zend_types.h`)(295)(313);
+ }
+ >
+
+ +frame{zend_valueの定義}<
+ +code-block-c(zend-value-def);
+ +p{
+ どれが入っているのかをどう区別する?
+ }
+ >
+
+ +frame{zvalの定義}<
+ +code-block-c(zval-def);
+ +p{
+ \inline-code(`type_info`);が型情報を保持している
+ }
+ +p{
+ この値を見て、\inline-code(`zend_value`);に何が入っているかを区別する
+ }
+ +p{
+ いわゆる"tagged-union"
+ }
+ >
+
+ +frame{PHPの型}<
+ +code-block-c(zval-types);
+ +p{
+ 参照は\inline-code(`IS_REFERENCE`);
+ }
+ +p{
+ 内部的には、独立した型として実装されている
+ }
+ >
+
+ +frame{PHPの型}<
+ +code-block-c(zend-value-def);
+ +p{
+ \inline-code(`zend_reference`);はどんなデータ構造か?
+ }
+ >
+
+ +frame{zend_referenceの定義}<
+ +code-block-c(zend-reference-def);
+ +p{
+ \php-src-link(`Zend/zend_types.h`)(537)(541);
+ }
+ +p{
+ 参照カウント: 同じ値への参照がどれだけあるか?
+ }
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$x: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 50pt
+ )<
+ +code-block-php(`$x = 1;`);
+ >
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$x: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: ???};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{???} |> vmargin 10pt |> hmargin 75pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 15pt;
+ textbox{\$y: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: ???};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{???} |> vmargin 10pt |> hmargin 75pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 50pt
+ )<
+ +code-block-php(`$x = 1;
+$y =& $x;`);
+ >
+ >
+ >
+
+ +section{|参照代入|}<
+ +frame{zend_assign_to_variable_reference}<
+ +fig-on-right(
+ vconcat [
+ textbox{\inline-code(`$lhs =& $rhs;`);};
+ gap 5pt;
+ textbox{\inline-code(`$lhs`);=左辺};
+ gap 5pt;
+ textbox{\inline-code(`$rhs`);=右辺};
+ ]
+ )<
+ +code-block-c(zend-assign-to-variable-reference-def);
+ +p{
+ \php-src-link(`Zend/zend_execute.c`)(533)(557);
+ }
+ >
+ >
+
+ +frame{ZVAL_NEW_REF}<
+ +code-block-c(zval-new-ref-def);
+ +p{
+ \php-src-link(`Zend/zend_types.h`)(1077)(1086);
+ }
+ +p{
+ \inline-code(`z`);の中身を参照でラップする
+ }
+ >
+
+ +frame{zend_assign_to_variable_reference}<
+ +code-block-c(zend-assign-to-variable-reference-def);
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$rhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 25pt
+ )<
+ +code-block-php(`$rhs = 1;
+$lhs =& $rhs;
+`);
+ +code-block-c(zend-assign-to-variable-reference-simple);
+ >
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$rhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 25pt
+ )<
+ +code-block-php(`$rhs = 1;
+$lhs =& $rhs;
+`);
+ +code-block-c(zval-new-ref-simple);
+ >
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$rhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 15pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 1};
+ gap 10pt;
+ textbox{val: zval};
+ gap 5pt;
+ textbox{\<uninitialized\>} |> vmargin 15pt |> hmargin 25pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(`$rhs = 1;
+$lhs =& $rhs;
+`);
+ +code-block-c(zval-new-ref-simple);
+ >
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$rhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 15pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 1};
+ gap 10pt;
+ textbox{val: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 5pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 5pt |> hmargin 80pt |> frame 1pt (Color.gray 0.5);
+ ] |> hvmargin 5pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(`$rhs = 1;
+$lhs =& $rhs;
+`);
+ +code-block-c(zval-new-ref-simple);
+ >
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$rhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_REFERENCE};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 100pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 30pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 1};
+ gap 10pt;
+ textbox{val: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 5pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 5pt |> hmargin 80pt |> frame 1pt (Color.gray 0.5);
+ ] |> hvmargin 10pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(`$rhs = 1;
+$lhs =& $rhs;
+`);
+ +code-block-c(zval-new-ref-simple);
+ >
+ +fig-arrow((555pt, 250pt))((555pt, 200pt));
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$rhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_REFERENCE};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 100pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 30pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 1};
+ gap 10pt;
+ textbox{val: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 5pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 5pt |> hmargin 80pt |> frame 1pt (Color.gray 0.5);
+ ] |> hvmargin 10pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(`$rhs = 1;
+$lhs =& $rhs;
+`);
+ +code-block-c(zend-assign-to-variable-reference-simple);
+ >
+ +fig-arrow((555pt, 250pt))((555pt, 200pt));
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$rhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_REFERENCE};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 100pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 30pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 2};
+ gap 10pt;
+ textbox{val: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 5pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 5pt |> hmargin 80pt |> frame 1pt (Color.gray 0.5);
+ ] |> hvmargin 10pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(`$rhs = 1;
+$lhs =& $rhs;
+`);
+ +code-block-c(zend-assign-to-variable-reference-simple);
+ >
+ +fig-arrow((555pt, 250pt))((555pt, 200pt));
+ >
+
+ +frame{具体例}<
+ +fig-on-right(
+ vconcat [
+ textbox{\$rhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_REFERENCE};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 100pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 30pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 2};
+ gap 10pt;
+ textbox{val: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_LONG};
+ gap 5pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{1} |> vmargin 5pt |> hmargin 80pt |> frame 1pt (Color.gray 0.5);
+ ] |> hvmargin 10pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(`$rhs = 1;
+$lhs =& $rhs;
+`);
+ +code-block-c(zend-assign-to-variable-reference-simple);
+ >
+ +fig-abs-pos((190pt, 215pt))(
+ from-bbox-graphics [
+ Gr.rectangle (0pt, 0pt) (250pt, 140pt) |> fill (Color.of-css `#EEEEEE`)
+ ]
+ );
+ +fig-abs-pos((180pt, 225pt))(
+ vconcat [
+ textbox{\$lhs: zval};
+ gap 5pt;
+ vconcat [
+ textbox{type_info: IS_REFERENCE};
+ gap 10pt;
+ textbox{value: zend_value};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 100pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ );
+ +fig-arrow((555pt, 250pt))((555pt, 200pt));
+ +fig-arrow((500pt, 217pt))((500pt, 200pt));
+ +fig-abs-pos((305pt, 217pt))(
+ from-bbox-graphics [
+ Gr.poly-line (0pt, 30pt) [(0pt, 0pt); (199pt, 0pt)] |> stroke 3pt Color.black;
+ ]
+ );
+ >
+ >
+ >
+
+ +section{|クイズの解説|}<
+ +frame{クイズの解説: Q1}<
+ +code-block-php(quiz-1-a);
+ >
+
+ +frame{クイズの解説: Q1}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$y};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 30pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 2};
+ gap 10pt;
+ textbox{zval};
+ gap 5pt;
+ textbox{42} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-1-a);
+ >
+ +fig-arrow((610pt, 310pt))((610pt, 270pt));
+ +fig-arrow((530pt, 310pt))((530pt, 270pt));
+ >
+
+ +frame{クイズの解説: Q2}<
+ +code-block-php(quiz-2-a);
+ >
+
+ +frame{クイズの解説: Q2}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$y};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 30pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 2};
+ gap 10pt;
+ textbox{zval};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-2-a);
+ >
+ +fig-arrow((610pt, 310pt))((610pt, 270pt));
+ +fig-arrow((530pt, 310pt))((530pt, 270pt));
+ >
+
+ +frame{クイズの解説: Q2}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$y};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 30pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 2};
+ gap 10pt;
+ textbox{zval};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 10pt;
+ vconcat [
+ textbox{\$z};
+ gap 5pt;
+ textbox{1} |> vmargin 15pt |> hmargin 35pt |> frame 2pt (Color.black);
+ ]
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-2-a);
+ >
+ +fig-arrow((610pt, 310pt))((610pt, 270pt));
+ +fig-arrow((530pt, 310pt))((530pt, 270pt));
+ >
+
+ +frame{クイズの解説: Q2}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$y};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 30pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 2};
+ gap 10pt;
+ textbox{zval};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ gap 10pt;
+ vconcat [
+ textbox{\$z};
+ gap 5pt;
+ textbox{42} |> vmargin 15pt |> hmargin 35pt |> frame 2pt (Color.black);
+ ]
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-2-a);
+ >
+ +fig-arrow((610pt, 310pt))((610pt, 270pt));
+ +fig-arrow((530pt, 310pt))((530pt, 270pt));
+ >
+
+ +frame{クイズの解説: Q3}<
+ +code-block-php(quiz-3-a);
+ >
+
+ +frame{クイズの解説: Q3}<
+ +fig-on-right(
+ vconcat [
+ vconcat [
+ textbox{\$xs};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{zval};
+ gap 5pt;
+ textbox{1} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{zval};
+ gap 5pt;
+ textbox{2} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-3-a);
+ >
+ +fig-arrow((610pt, 310pt))((610pt, 280pt));
+ +fig-arrow((595pt, 240pt))((595pt, 210pt));
+ +fig-arrow((635pt, 240pt))((635pt, 210pt));
+ >
+
+ +frame{クイズの解説: Q3}<
+ +fig-on-right(
+ vconcat [
+ vconcat [
+ textbox{\$xs};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{} |> vmargin 17pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{2} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 1};
+ gap 10pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-3-a);
+ >
+ +fig-arrow((530pt, 310pt))((530pt, 280pt));
+ +fig-arrow((515pt, 240pt))((515pt, 210pt));
+ +fig-arrow((555pt, 240pt))((555pt, 210pt));
+ +fig-arrow((515pt, 185pt))((515pt, 155pt));
+ >
+
+ +frame{クイズの解説: Q3}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$xs};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 40pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{} |> vmargin 17pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{2} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 2};
+ gap 10pt;
+ textbox{1} |> vmargin 10pt |> hmargin 80pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-3-a);
+ >
+ +fig-arrow((530pt, 310pt))((530pt, 280pt));
+ +fig-arrow((515pt, 240pt))((515pt, 210pt));
+ +fig-arrow((555pt, 240pt))((555pt, 210pt));
+ +fig-arrow((515pt, 185pt))((515pt, 155pt));
+ +fig-arrow((630pt, 310pt))((630pt, 155pt));
+ >
+
+ +frame{クイズの解説: Q3}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$xs};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 40pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{} |> vmargin 17pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{2} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 2};
+ gap 10pt;
+ textbox{42} |> vmargin 10pt |> hmargin 75pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-3-a);
+ >
+ +fig-arrow((530pt, 310pt))((530pt, 280pt));
+ +fig-arrow((515pt, 240pt))((515pt, 210pt));
+ +fig-arrow((555pt, 240pt))((555pt, 210pt));
+ +fig-arrow((515pt, 185pt))((515pt, 155pt));
+ +fig-arrow((630pt, 310pt))((630pt, 155pt));
+ >
+
+ +frame{クイズの解説: Q4}<
+ +code-block-php(quiz-4-a);
+ >
+
+ +frame{クイズの解説: Q4}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$xs};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 40pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{} |> vmargin 16.5pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{2} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 3};
+ gap 10pt;
+ textbox{1} |> vmargin 10pt |> hmargin 70pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-4-a);
+ >
+ +fig-arrow((545pt, 310pt))((545pt, 280pt));
+ +fig-arrow((530pt, 240pt))((530pt, 210pt));
+ +fig-arrow((580pt, 240pt))((580pt, 210pt));
+ +fig-arrow((530pt, 185pt))((530pt, 155pt));
+ +fig-arrow((650pt, 310pt))((650pt, 155pt));
+ >
+
+ +frame{クイズの解説: Q4}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$xs};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 40pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{} |> vmargin 16.5pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{2} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 3};
+ gap 10pt;
+ textbox{1} |> vmargin 10pt |> hmargin 70pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-4-a);
+ >
+ +fig-abs-pos((360pt, 155pt))(
+ from-bbox-graphics [
+ Gr.rectangle (0pt, 0pt) (125pt, 200pt) |> fill (Color.of-css `#EEEEEE`)
+ ]
+ );
+ +fig-abs-pos((350pt, 170pt))(
+ vconcat [
+ vconcat [
+ textbox{\$ys};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{} |> vmargin 16.5pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{2} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ ] |> hmargin 20pt
+ );
+ +fig-arrow((545pt, 310pt))((545pt, 280pt));
+ +fig-arrow((530pt, 240pt))((530pt, 210pt));
+ +fig-arrow((580pt, 240pt))((580pt, 210pt));
+ +fig-arrow((530pt, 185pt))((530pt, 155pt));
+ +fig-arrow((650pt, 310pt))((650pt, 155pt));
+ +fig-arrow((405pt, 310pt))((405pt, 280pt));
+ +fig-arrow((390pt, 240pt))((390pt, 210pt));
+ +fig-arrow((440pt, 240pt))((440pt, 210pt));
+ +fig-arrow((510pt, 165pt))((510pt, 155pt));
+ +fig-abs-pos((392pt, 165pt))(
+ from-bbox-graphics [
+ Gr.poly-line (0pt, 20pt) [(0pt, 0pt); (122pt, 0pt)] |> stroke 3pt Color.black;
+ ]
+ );
+ >
+
+ +frame{クイズの解説: Q4}<
+ +fig-on-right(
+ vconcat [
+ hconcat [
+ vconcat [
+ textbox{\$xs};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 40pt;
+ vconcat [
+ textbox{\$x};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{} |> vmargin 16.5pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{2} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ gap 20pt;
+ textbox{zend_reference};
+ gap 5pt;
+ vconcat [
+ textbox{refcount: 3};
+ gap 10pt;
+ textbox{42} |> vmargin 10pt |> hmargin 65pt |> frame 1.5pt (Color.gray 0.25);
+ ] |> hvmargin 10pt |> frame 2pt Color.black;
+ ] |> hmargin 20pt
+ )<
+ +code-block-php(quiz-4-a);
+ >
+ +fig-abs-pos((360pt, 155pt))(
+ from-bbox-graphics [
+ Gr.rectangle (0pt, 0pt) (125pt, 200pt) |> fill (Color.of-css `#EEEEEE`)
+ ]
+ );
+ +fig-abs-pos((350pt, 170pt))(
+ vconcat [
+ vconcat [
+ textbox{\$ys};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 40pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ vconcat [
+ textbox{zend_array};
+ gap 5pt;
+ textbox{} |> vmargin 15pt |> hmargin 50pt |> frame 2pt (Color.black);
+ ];
+ gap 20pt;
+ hconcat [
+ vconcat [
+ textbox{} |> vmargin 16.5pt |> hmargin 24pt |> frame 2pt (Color.black);
+ ];
+ gap 10pt;
+ vconcat [
+ textbox{3} |> vmargin 10pt |> hmargin 20pt |> frame 2pt (Color.black);
+ ];
+ ];
+ ] |> hmargin 20pt
+ );
+ +fig-arrow((545pt, 310pt))((545pt, 280pt));
+ +fig-arrow((530pt, 240pt))((530pt, 210pt));
+ +fig-arrow((580pt, 240pt))((580pt, 210pt));
+ +fig-arrow((530pt, 185pt))((530pt, 155pt));
+ +fig-arrow((650pt, 310pt))((650pt, 155pt));
+ +fig-arrow((405pt, 310pt))((405pt, 280pt));
+ +fig-arrow((390pt, 240pt))((390pt, 210pt));
+ +fig-arrow((440pt, 240pt))((440pt, 210pt));
+ +fig-arrow((510pt, 165pt))((510pt, 155pt));
+ +fig-abs-pos((392pt, 165pt))(
+ from-bbox-graphics [
+ Gr.poly-line (0pt, 20pt) [(0pt, 0pt); (122pt, 0pt)] |> stroke 3pt Color.black;
+ ]
+ );
+ >
+ >
+
+ +frame{まとめ}<
+ +listing{
+ * Cが読めると世界が広がる
+ ** PHP、Apache httpd、MySQL等
+ * PHPの処理系を気軽に読もう
+ }
+ >
+
+ +section{|おまけ|}<
+ +section{|入り切らなかったクイズ|}<
+ +frame{参照の不思議クイズ: Q5}<
+ +code-block-php(quiz-5-q);
+ >
+
+ +frame{参照の不思議クイズ: Q5}<
+ +code-block-php(quiz-5-a);
+ >
+
+ +frame{参照の不思議クイズ: Q6}<
+ +code-block-php(quiz-6-q);
+ >
+
+ +frame{参照の不思議クイズ: Q6}<
+ +code-block-php(quiz-6-a);
+ >
+ >
+ >
+>
+
+% vim: fdm=marker fdl=99