Go 语言第一课

02 设计哲学 设计哲学之于编程语言,就好比一个人的价值观之于这个人的行为。 简单:Go 生产力的源泉。 显式:Go 希望开发人员 明确知道自己在做什么;显式的基于值比较的错误处理方案。 组合:类型嵌入(Type Embedding)。 并发:面向多核、原生支持并发、用户层轻量级线程 goroutine。 面向工程:将解决工程问题作为 Go 的 设计原则之一,这些问题包括:程序构建慢、依赖管理失控、代码难于理 解、跨语言构建难等。 03 配好环境 https://go.dev/doc/devel/release https://golang.google.cn/dl/ 安装多个 Go 版本 go get golang.org/dl/go1.15.13 go1.15.13 download go1.15.13 version 配置 Go go env go help environment 04 Go 程序的结构 import "fmt" 一行中 fmt 代表的是包的导入路径(Import),它表示的是标准库下的 fmt 目录,整个 import 声明语句的含义是导入标准库 fmt 目录下的包 fmt.Println 函数调用一行中的 fmt 代表的则是包名。 通常导入路径的最后一个分段名与包名是相同的,这也很容易让人误解 import 声明语句中的 fmt 指的是包名,其实并不是这样的。 gofmt main.go Go module go mod init go mod tidy 05 Go 项目的布局标准 loccount 工具 ...

February 1, 2023 · 5 min · 1061 words · Me

回顾 2022

犯错的人不会沉浸在错误里,而是继续战斗。 —— 管泽元 S12 总决赛 DRX vs SKT 2:2 – EOF –

December 31, 2022 · 1 min · 12 words · Me

PHP Migrating 8.0 to 8.1

实验环境:https://onlinephp.io/ https://www.php.net/releases/8.1/en.php https://www.php.net/manual/en/migration81.php https://php.watch/versions/8.1 https://github.com/symfony/polyfill/tree/1.x/src/Php81 PHP 8.1 contains many new features, including enums, readonly properties, first-class callable syntax, fibers, intersection types, performance improvements and more. New Features 8.1 // Add native support for enumerations using enum keyword // https://www.php.net/manual/en/language.enumerations.examples.php enum Status: string { case Draft = 'draft'; case Published = 'published'; case Archived = 'archived'; } class BlogPost { public function __construct( public Status $status = Status::Draft ) {} } // Readonly properties // Properties can be marked as immutable after initialization class User { public readonly string $uuid; public function __construct(string $uuid) { $this->uuid = $uuid; } } // Fibers, new concurrency primitive for managing green threads // https://www.php.net/manual/en/language.fibers.php $fiber = new Fiber(function(): void { echo "Starting fiber\n"; Fiber::suspend(); echo "Resuming fiber\n"; }); $fiber->start(); echo "...\n"; $fiber->resume(); // Starting fiber // ... // Resuming fiber // Intersection Types, combine multiple type constraints // 交叉类型 function countItems(Iterator&Countable $items): int { return count($items); } // Never Return Type // Indicates function never returns function redirect(string $url): never { header("Location: $url"); exit(); } // First-Class Callable Syntax // Replaces Closure::fromCallable() with cleaner syntax $strlen = strlen(...); echo $strlen('hello'); // 5 // same as $fn = Closure::fromCallable('strlen'); echo $fn('hello'); // 5 $words = ['apple', 'banana']; var_dump(array_map(strlen(...), $words)); // [5, 6] class Calculator { public function add(int $a, int $b): int { return $a + $b; } public function __invoke(int $x) { return $x * 2; } } $calc = new Calculator(); $addCallable = $calc->add(...); echo $addCallable(3, 5); // 8 $invocable = $calc(...); echo $invocable(10); // 20 // New Array Features // String key unpacking $arr1 = [1, 'a' => 'b']; var_dump([...$arr1, 'c' => 'd']); // [1,'a' => 'b', 'c' => 'd'] // 参数解包后的命名参数 function foo($a, $b, $c) { var_dump($a, $b, $c); } foo(...[1,2], c: 3); // File System Improvements $file = fopen('data.txt', 'w'); fwrite($file, 'content'); fsync($file); // Force write to disk fclose($file); // Objects in default parameters // 现在可以使用 new ClassName() 表达式作为参数、静态变量、全局常量初始值设定项和属性参数的默认值 // 现在也可以将对象传递给 define() class Logger { public function __construct( private Formatter $fmt = new DefaultFormatter() ) {} } // 八进制 var_dump(0o14); // int(12) New Functions 8.1 // 如果数组的键由从 0 到 count($array)-1 的连续数字组成,则数组被认为是 list array_is_list([]); // true array_is_list(['apple', 2, 3]); // true array_is_list([0 => 'apple', 'orange']); // true // The array does not start at 0 array_is_list([1 => 'apple', 'orange']); // false Backward Incompatible Changes 8.1 // Usage of static Variables in Inherited Methods ¶ class A { public static function counter() { static $i = 0; return ++$i; } } class B extends A {} var_dump(A::counter()); // int(1) var_dump(A::counter()); // int(2) var_dump(B::counter()); // PHP 8.0 int(1) // PHP 8.1+ int(3) Deprecated 8.1 // Implicit incompatible float to int conversions $arr = []; $arr[3.14] = 'value'; // Deprecated(键值3.14转为3) $arr[(int)3.14] = 'value'; // 显式转换避免警告 – EOF – ...

December 21, 2022 · 3 min · 454 words · Me

PHP Migrating 7.4 to 8.0

实验环境:https://onlinephp.io/ https://www.php.net/releases/8.0/en.php https://www.php.net/manual/en/migration80.php https://php.watch/versions/8.0 https://github.com/symfony/polyfill/tree/1.x/src/Php80 PHP 8.0 contains many new features and optimizations including named arguments, union types, attributes, constructor property promotion, match expression, nullsafe operator, JIT, and improvements in the type system, error handling, and consistency. New Features 8.0 // Named Parameters 命名参数 // https://www.php.net/manual/zh/functions.arguments.php#functions.named-arguments // array_fill(int $start_index, int $count, mixed $value): array var_dump(array_fill(value: 50, count: 3, start_index: 0)); // PHP80 [50, 50, 50] // 注解(Attributes) // https://www.php.net/manual/zh/language.attributes.php // 定义注解 -> 使用注解 -> (通过反射)提取注释 // 注意以后用词:Attributes 注解,Properties 属性 #[\Attribute] class JsonSerialize { public function __construct(public ?string $fieldName = null) { var_dump("JsonSerialize:$fieldName"); } } class VersionedObject { #[JsonSerialize('json-foobar')] protected string $myValue = ''; } $object = new VersionedObject(); $reflection = new ReflectionObject($object); foreach ($reflection->getProperties() as $reflectionProp) { foreach ($reflectionProp->getAttributes(JsonSerialize::class) as $jsonSerializeAttr) { var_dump($jsonSerializeAttr->getName()); var_dump($jsonSerializeAttr->getArguments()); var_dump($jsonSerializeAttr->getTarget()); var_dump($jsonSerializeAttr->isRepeated()); var_dump($jsonSerializeAttr->newInstance()); } } // string(13) "JsonSerialize" // // array(1) { // [0]=> // string(11) "json-foobar" // } // // int(8) Attribute::TARGET_PROPERTY // // bool(false) // // string(25) "JsonSerialize:json-foobar" // object(JsonSerialize)#5 (1) { // ["fieldName"]=> // string(11) "json-foobar" // } // 构造器属性提升 Constructor Property Promotion // 当构造器参数带访问控制(visibility modifier)时,PHP 会同时把它当作对象属性和构造器参数,并赋值到属性 class Point { public function __construct(protected int $x, protected int $y = 0) {} } var_dump(new Point(2,4)); // object(Point)#1 (2) { // ["x":protected]=> // int(2) // ["y":protected]=> // int(4) // } class Point2 { protected int $x; protected int $y; public function __construct(protected int $x, protected int $y = 0) {} } // 此类中已经定义了具有相同名称的字段 // Fatal error: Cannot redeclare Point::$x // Union types 联合类型 // ?T is same T|null // // - 类型只能出现一次 int|string|INT 否则报错 // - 使用 mixed 会报错 // - bool 与 false or true 不能混用 // - object 与 class 不能混用 // - iterable 与 array Traversable 不能混用 // - 使用 self、parent 或 static 都会导致错误 public function parse_value(string|int|float): string|null {} // match 表达式 // https://www.php.net/manual/en/control-structures.match.php // match 表达式必须是详尽,则会抛出 UnhandledMatchError。 echo match (8.0) { '8.0' => "Oh no!", 8.0 => "This matches", }; // This matches // Nullsafe Operator $result = $repository?->getUser(5)?->name; // Is equivalent to the following code block: if (is_null($repository)) { $result = null; } else { $user = $repository->getUser(5); if (is_null($user)) { $result = null; } else { $result = $user->name; } } // Argument Unpacking echo str_replace(...[ 'replace' => 'Iron Man', 'search' => 'Inevitable', 'subject' => 'I am Inevitable', ]); // Named Parameters with Variadic Parameters function test($a, $b, ...$args) { var_dump($args); } test(28, 15, june: 6, september: 15, january: "01"); // array(3) { // ["june"]=> int(6) // ["september"]=> int(15) // ["january"]=> string(2) "01" // } // JIT Just-In-Time Compilation // php -i | grep -i opcache // php -d opcache.enable_cli=1 -d opcache.jit_buffer_size=256M -d opcache.jit=tracing -i | grep -i jit // opcache.enable=1 // opcache.enable_cli=1 // opcache.jit_buffer_size=256M <?php function fibonacci($n) { if ($n < 2) return $n; return fibonacci($n - 1) + fibonacci($n - 2); } $start = microtime(true); fibonacci(42); $end = microtime(true); echo "Time taken: " . ($end - $start) . " seconds\n"; // php -d opcache.enable_cli=1 -d opcache.jit_buffer_size=256M -d opcache.jit=tracing test.php // The WeakMap class has been added, accepts objects as keys, similar SplObjectStorage // https://www.php.net/manual/en/class.weakmap.php // https://www.php.net/manual/en/class.splobjectstorage.php // final class WeakMap implements ArrayAccess, Countable, IteratorAggregate $wm = new WeakMap(); $o = new StdClass; class A { public function __destruct() { echo "Dead!\n"; } } $wm[$o] = new A; var_dump(count($wm)); // int(1) unset($o); // Dead! // 销毁 var_dump(count($wm)); // int(0) // 对比 SplObjectStorage $wm = new SplObjectStorage(); $o = new StdClass; class A { public function __destruct() { echo "Dead!\n"; } } $wm[$o] = new A; var_dump(count($wm)); // int(1) unset($o); // 未销毁 var_dump(count($wm)); // int(1) // 只要类型兼容,现在可以将任意数量的函数参数替换为可变参数 variadic argument class A { public function method(int $many, string $parameters, $here) {} } class B extends A { public function method(...$everything) {} } // OK class C extends A { public function method(int ...$everything) {} } // Fatal error: Declaration of C::method(int ...$everything) // static 后期静态绑定,现在可以用作返回类型 class Test { public function create(): static { return new static(); } } // get_class($obj) === $obj::class class Test {} $obj = new Test; var_dump($obj::class); var_dump(get_class($obj)); // new instanceof 可以与任意表达式一起使用 // new (expression)(...$args) // $obj instanceof (expression) class A{}; class B{}; new (1>2 ? "A" : "B")(); // 新增 Stringable 接口。如果 class 定义了 __toString(),则自动实现了此接口 // Traits can define abstract private methods trait T { abstract private function a(); } // Throw 可以作为一个表达式 as an expression $value = $config['path'] ?? throw new InvalidArgumentException('path required'); $fn = fn() => throw new Exception('Exception in arrow function'); // 参数列表中现在允许使用可选的尾随逗号 function functionWithLongSignature( Type1 $parameter1, Type2 $parameter2, // <-- This comma is now allowed. ) {} // 允许 catch (Exception) 无需存储到变量 try {} catch (Exception) {} // 在父类上声明的私有方法不再对子类的方法强制执行任何继承规则(私有构造函数除外) class ParentClass { private function method1() {} private function method2() {} private static function method3() {} } abstract class ChildClass extends ParentClass { public abstract function method1(); public static function method2() {} public function method3() {} } // OK // New string functions str_contains('Foobar', 'Foo'); // true str_starts_with('PHP 8', 'PHP'); // true str_ends_with('Version8', '8'); // true Backward Incompatible Changes 8.0 // 字符串与数字比较 // 0 == "not-a-number" is false // 将数字转换为字符串,并使用字符串比较 var_dump(0 == "foo"); var_dump(42 == "42foo"); var_dump(0 == ""); // PHP80 PHP74 // bool(false) true // bool(false) true // bool(false) true var_dump("" < 0); var_dump("" < -1); var_dump("a" < 0); var_dump("b" < -1); var_dump("ab" > 0); // PHP80 PHP74 // bool(true) false // bool(true) false // bool(false) false // bool(false) false // bool(true) false // is_callable() 在检查具有 classname 的 non-static 方法时将 false(必须检查对象实例) class Test { public function method1() {} } var_dump(is_callable([Test::class, 'method1'])); var_dump(is_callable([new Test, 'method1'])); // PHP80 PHP74 // bool(false) true // bool(true) true // __autoload() function has been removed // 删除了对 object 使用 array_key_exists() 的能力。isset() or property_exists() may be used instead // isset($arr['key']) → false(当值为 null)- 只能在 null 安全时检查,无法区分 null 与 不存在 // array_key_exists('key', $arr) → true(即使值为 null)- 可以区分存在但值为 null 的情况 – EOF – ...

December 14, 2022 · 5 min · 942 words · Me

PHP Migrating to 7.2 7.3 7.4

实验环境:https://onlinephp.io/ PHP7.1 to PHP7.2 https://www.php.net/manual/en/migration72.php https://php.watch/versions/7.2 Argon2 password hashing support, class constant visibility, object type, and many more. New Features 7.2 // 新的 object 类型 // 可用于逆变(contravariant)参数输入和协变(covariant)返回任何对象类型 // https://www.php.net/manual/zh/language.oop5.variance.php // 协变使子类比父类方法能返回更具体的类型;逆变使子类比父类方法参数类型能接受更模糊的类型 function test(object $obj): object { return new SplQueue(); } test(new StdClass()); // 抽象类可以重写被继承的抽象类的抽象方法 abstract class A { abstract function test(string $s); } abstract class B extends A { // overridden - 仍然保持参数的逆变和返回的逆变 abstract function test($s): int; } // 重写方法和接口实现的参数类型可以省略 // 仍然是符合LSP,这种参数类型是逆变 interface A { public function test(array $input); } class B implements A { // type omitted for $input public function test($input){ return $input; } } var_dump((new B())->test(1)); // PHP72 int(1) // // PHP71 Fatal error: Declaration of B::test($input) must be compatible with A::test(array $input) Backward incompatible changes 7.2 // 防止 number_format() 返回负零 var_dump(number_format(-0.01)); // PHP72 string(1) "0" // // PHP71 string(2) "-0" // 转换对象和数组中的数字键 $arr = [0 => 1]; $obj = (object) $arr; var_dump($obj); var_dump($obj->{'0'}, // 新写法 $obj->{0} // 新写法 ); // PHP72 object(stdClass)#1 (1) { // ["0"]=> // int(1) // } // int(1) // int(1) // // PHP71 object(stdClass)#1 (1) { // [0]=> // int(1) // } // Notice: Undefined property: stdClass::$0 $obj = new class { public function __construct() { $this->{1} = "value"; } }; $arr = (array) $obj; var_dump($arr); var_dump($arr["1"]); // 整数 或者 字符串整数 含义相同 var_dump($arr[1]); // PHP71 var_dump($arr[0]); // PHP72 array(1) { // [1]=> // string(2) "my" // } // // PHP71 无法取整型字符串 key // array(1) { // ["1"]=> // string(2) "my" // } // Notice: Undefined offset: 1 // Notice: Undefined offset: 1 // Notice: Undefined offset: 0 $a = [1.3 => "v1", 1.4 => "v2"]; var_dump($a); // ALL array key float 会被转换为 int // array(1) { // [1]=> // string(2) "v2" // } // get_class() 函数不再接受 null var_dump(get_class(null)); // PHP72 // Warning: get_class() expects parameter 1 to be object // bool(false) // // PHP71 // Warning: get_class() called without object from outside a class // bool(false) // // PHP80 // Fatal error: Uncaught TypeError: get_class(): Argument #1 ($object) must be of type object, null given // 计算非可数类型(non-countable)时发出警告 var_dump( count(null), // NULL is not countable count(1), // integers are not countable count('abc'), // strings are not countable count(new stdclass) // objects not implementing the Countable interface are not countable ); // PHP72 // Warning: count(): Parameter must be an array or an object that implements Countable // // PHP71 // 无 Warning // // PHP80 // Fatal error: Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array // 调用未定义的常量,现在会抛出一个 E_WARNING 错误(之前版本中为 E_NOTICE)) // PHP8 将不会转化成他们自身的字符串,同时抛出 Error 异常 var_dump(MY_CONST); // PHP72 // Warning: Use of undefined constant MY_CONST - assumed 'MY_CONST' // string(8) "MY_CONST" // // PHP71 // Notice: Use of undefined constant MY_CONST // string(8) "MY_CONST" // // PHP80 // Fatal error: Uncaught Error: Undefined constant "MY_CONST" // bcmod 任意精度数字取模,添加新增参数 scale var_dump(bcmod("4", "3.5")); // PHP72 // string(1) "0" // // PHP71 // string(1) "1" var_dump(bcmod("4", "3.5", 1)); // PHP72 // string(3) "0.5" // // PHP71 // Warning: bcmod() expects exactly 2 parameters, 3 given // json_decode associative 允许为 null // 当为 true 时,JSON 对象将返回关联 array;当为 false 时,JSON 对象将返回 object。 // 当为 null 时,JSON 对象将返回关联 array 或 object,这取决于是否在 flags 中设置 JSON_OBJECT_AS_ARRAY // https://www.php.net/manual/zh/function.json-decode.php $json = '{"a":1,"b":2}'; var_dump(json_decode($json, null, 512, JSON_OBJECT_AS_ARRAY)); // PHP72 // array(2) { // ["a"]=> // int(1) // ["b"]=> // int(2) // } // // PHP71 // object(stdClass)#1 (2) { // ["a"]=> // int(1) // ["b"]=> // int(2) // } PHP7.2 to PHP7.3 https://www.php.net/manual/en/migration72.php https://php.watch/versions/7.3 Heredoc/nowdoc syntax improvements and a bunch of legacy code deprecations. ...

December 12, 2022 · 7 min · 1281 words · Me

PHP Migrating to 7.0 7.1

实验环境:https://onlinephp.io/ Polyfill https://github.com/symfony/polyfill/tree/main/src PHP7.0 to PHP7.1 https://www.php.net/manual/en/migration71.php 7.1 New Features // Nullable types 可为空类型 function test(?string $name): ?string // Void 函数 function swap(&$left, &$right) : void // 获取一个 void 方法的返回值会得到 null,并且不会产生任何警告 // 对称数组解构 $data = [ [1, 'Tom'], [2, 'Fred'], ]; [$id, $name] = $data[0]; // 赋值部分 [, $name1] = $data[1]; foreach ($data as [$id, $name]) { // logic here with $id and $name } function swap(&$a, &$b): void { [$a, $b] = [$b, $a]; } // list 支持键名 $data = [ ["id" => 1, "name" => 'Tom'], ["id" => 2, "name" => 'Fred'], ]; foreach ($data as ["name" => $name, "id" => $id]) { // logic here with $id and $name } // 类常量支持可见性 class ConstDemo { public const PUBLIC_CONST_A = 1; } // iterable 伪类(与 callable 类似) interface Traversable extends iterable { // 这个接口没有任何方法,它的作用仅仅是作为所有可遍历类的基本接口 // Traversable as part of either Iterator or IteratorAggregate,不能直接实现 } function iterator(iterable $iter) { foreach ($iter as $val) { // ... } } // 多异常捕获处理,可以通过管道字符(|)来实现多个异常的捕获 try { // some code } catch (FirstException | SecondException $e) { // handle first and second exceptions } // 支持为负的字符串偏移量,一个负数的偏移量会被理解为一个从字符串结尾开始的偏移量 // 所有支持偏移量的字符串操作函数,都支持接受负数作为偏移量 // 中文操作要小心 var_dump("abcdef"[-2]); // e var_dump(strpos("aabbcc", "b")); // 2 var_dump(strpos("aabbcc", "b", -3)); // 3 // 新增 Closure::fromCallable(),将 callable 转为一个 Closure 对象 // public static Closure::fromCallable(callable $callback): Closure class Test { public function exposeFunction() { return Closure::fromCallable([$this, 'privateFunction']); } private function privateFunction($param) { var_dump($param); } } $privFunc = (new Test)->exposeFunction(); $privFunc('some value'); // string(10) "some value" 7.1 New Functions // 否为可迭代 is_iterable() 7.1 Backward Incompatible Changes // 当传递参数过少时将抛出错误 function test($param){} test(); /* PHP71 Fatal error: Uncaught ArgumentCountError: Too few arguments to function test() PHP70 Warning: Missing argument 1 for test() */ // 禁止动态调用作用域自检函数 // $func() or array_map('extract', ...) // function array_map($callback, array $array, array ...$arrays): array (function () { $func = 'func_num_args'; $func(); })(); /* PHP71 Warning: Cannot call func_num_args() dynamically */ // 以下名称不能用于命名 class, interface, trait // - void // - iterable // 数字字符串转换 遵循科学记数法 var_dump(intval('1e5')); var_dump(is_numeric('1e5')); var_dump(is_numeric('e')); // PHP71 PHP70 // int(100000) int(1) // bool(true) bool(true) // bool(false) bool(false) // call_user_func() 不再支持对传址的函数的调用 error_reporting(E_ALL); function increment(&$var) { $var++; } $a = 0; call_user_func('increment', $a); // ...expected to be a reference, value given call_user_func_array('increment', [&$a]); // 1 $increment = 'increment'; $increment($a); // 2 // 字符串不再支持空索引运算符 $str = ""; $str[] = "abc"; var_dump($str); // PHP71 Fatal error: Uncaught Error: [] operator not supported for strings // PHP70 array(1) { // [0]=> // string(3) "abc" // } $a = ""; $a[0] = "hello world"; var_dump($a); // PHP71 string(1) "h" // PHP70 array(1) { // [0]=> // string(11) "hello world" // } // 通过空字符串上的字符串索引访问赋值 $str = ''; $str[10] = 'foo'; var_dump($str); // PHP71 string(11) " f" // PHP70 array(1) { // [10]=> // string(3) "foo" // } // 当通过引用赋值引用它们自动创建这些元素时,数组中元素的顺序已更改。 $array = []; $array['a'] = &$array['b']; $array['b'] = 1; var_dump($array); // PHP71 array(2) { // ["b"]=> // &int(1) // ["a"]=> // &int(1) // } // PHP70 array(2) { // ["a"]=> // &int(1) // ["b"]=> // &int(1) // } // 词法绑定变量不能重用名称,以下都将 fatal error $f = function () use ($_SERVER) {}; // any superglobals $f = function () use ($this) {}; $f = function ($param) use ($param) {}; // 禁止 "return;" 对于已经在编译时键入的返回值 function test(int $i): array { $i += 1; return; } // PHP Compile Error A function with return type must return a value var_dump('1b' + 'something'); // PHP71 // Notice: A non well formed numeric value encountered // Warning: A non-numeric value encountered // int(1) // PHP70 int(1) PHP5.6 to PHP7.0 https://www.php.net/manual/en/migration70.php Backward incompatible changes // 错误和异常处理相关的变更 // set_exception_handler() 不再保证收到的一定是 Exception 对象 function handler(Exception $e) { ... } set_exception_handler('handler'); // 兼容 PHP 5 和 7 function handler($e) { ... } // 仅支持 PHP 7 function handler(Throwable $e) { ... } // 当内部构造器失败的时候,总是抛出异常 // 间接调用的表达式的新旧解析顺序 // 现在严格遵循从左到右的顺序来解析 // 表达式 PHP 5 的解析方式 PHP 7 的解析方式 $$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz'] $foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz'] // foreach 通过值遍历时,操作的值为数组的副本 $array = [0]; foreach ($array as $val) { var_dump($val); $array[1] = 1; } // int(0) // foreach通过引用遍历时,有更好的迭代特性 $array = [0]; foreach ($array as &$val) { var_dump($val); $array[1] = 1; } // PHP 7.0 // int(0) // int(1) // PHP 5.6 // int(0) // call_user_method() and call_user_method_array() 被移除。 // 应该使用 call_user_func() 和 call_user_func_array() // 在函数中检视参数值会返回 当前 的值 function foo($x) { $x++; var_dump(func_get_arg(0)); } foo(1); // int(2) PHP 7.0 // int(1) PHP 5.6 7.0 New Features // 标量类型声明 // 返回值类型声明 function arraysSum(array ...$arrays): array { return array_map(function(array $array): int { return array_sum($array); }, $arrays); } // null 合并运算符,对 isset() 的简化 $username = $_GET['user'] ?? 'nobody'; // 太空船操作符(组合比较符) echo 1 <=> 1; // 0 echo 1 <=> 2; // -1 echo 2 <=> 1; // 1 // 通过 define() 定义 常量数组 define('ANIMALS', [ 'dog', 'cat', 'bird' ]); // 匿名类 用来替代一些“用后即焚”的完整类定义 $app = new Application; $app->setLogger(new class implements Logger { public function log(string $msg) { echo $msg; } }); // Unicode codepoint 转译语法 // 这接受一个以 16 进制形式的 Unicode codepoint echo "\u{9999}"; // 香 // Closure::call() 新方法,简化绑定一个方法到对象上闭包并调用它 // PHP 7 之前版本的代码 $getXCB = function() {return $this->x;}; // function bindTo($newThis, $newScope = 'static') { } // $newScope 将闭包关联到的类作用域 $getX = $getXCB->bindTo(new A, A::class); // 中间层闭包 echo $getX(); // PHP 7+ 及更高版本的代码 $getX = function() {return $this->x;}; echo $getX->call(new A); // 生成器委托 yield from function gen() { yield 1; yield 2; yield from gen2(); } function gen2() { yield 3; yield 4; } foreach (gen() as $val) { echo $val, PHP_EOL; } // 1 // 2 // 3 // 4 // 柯里化 function add($a) { return function($b) use ($a) { return $a + $b; }; } $result = add(10)(15); var_dump($result); // int 25 Deprecated features in PHP 7.0.x // 构造函数(方法名和类名一样)将被弃用,并在将来移除 class Foo { function foo() { echo 'I am the constructor'; } } // PHP 7.0: Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP // PHP 5.6: OK Other Changes // 放宽了保留词限制,以前不能用 'new'、'private' 和 'for' Project::new('Project Name')->private()->for('purpose here')->with('username here'); // class 关键词不能用于常量名,否则会和类名解析语法冲突(ClassName::class) New Global Constants PHP_INT_MIN – EOF – ...

November 28, 2022 · 5 min · 975 words · Me

Docker Code Snippet

Dockerfile ARG 构建参数 ARG <参数名>[=<默认值>] 该默认值可以在构建命令 docker build 中用 –build-arg <参数名>=<值> 来覆盖。 ARG LARADOCK_PHP_VERSION ARG BASE_IMAGE_TAG_PREFIX=latest FROM laradock/workspace:${BASE_IMAGE_TAG_PREFIX}-${LARADOCK_PHP_VERSION} LABEL maintainer="Mahmoud Zalt <mahmoud@zalt.me>" # ARG 指令有生效范围,如果在 FROM 指令之前指定,那么只能用于 FROM 指令中。 # 在 FROM 之后须再次指定 ARG ARG LARADOCK_PHP_VERSION Config Setting { "registry-mirrors": [ "https://mirror.ccs.tencentyun.com", "https://reg-mirror.qiniu.com", "https://hub-mirror.c.163.com", "https://mirror.baidubce.com" ] }

November 17, 2022 · 1 min · 47 words · Me

Laradock 学习笔记

Laradock 简介 Laradock 是一个基于 Docker 的完整 PHP 开发环境,专为 PHP 开发者(特别是 Laravel 开发者)设计。它提供了一套预配置的 Docker 容器,包含开发中常用的服务,如 Nginx、MySQL、Redis、PHP-FPM 等。 主要优势 开箱即用:预配置的开发环境,无需繁琐设置 一致性:确保开发、测试和生产环境的一致性 灵活性:支持多种 PHP 版本和扩展 模块化:可以根据需要启用或禁用特定服务 跨平台:在 Windows、macOS 和 Linux 上表现一致 基本架构 Laradock 采用模块化设计,每个服务都运行在独立的容器中,通过 Docker 网络连接: Workspace:包含开发工具的容器 PHP-FPM:PHP 解释器 Nginx/Apache:Web 服务器 MySQL/PostgreSQL/MongoDB:数据库 Redis/Memcached:缓存 其他辅助服务(邮件服务器、消息队列等) Dockerfile DEBIAN_FRONTEND ENV DEBIAN_FRONTEND=noninteractive DEBIAN_FRONTEND 环境变量用于告知操作系统应该从哪儿获得用户输入。 设置为 “noninteractive” 可以实现自动安装而无需用户交互,对于 CI/CD 流程和 Docker 构建特别有用。这在运行 apt-get 命令时尤为重要,因为它会自动选择默认选项并以最快速度完成构建。 最佳实践是在 RUN 命令中设置该变量,而不是使用 ENV 进行全局设置,因为全局设置会影响容器运行时的交互体验: RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ... 基于角色的用户配置 # 创建非 root 用户防止文件在宿主机上创建时具有 root 权限 ARG PUID=1000 ENV PUID ${PUID} ARG PGID=1000 ENV PGID ${PGID} RUN set -xe; \ groupadd -g ${PGID} laradock && \ useradd -l -u ${PUID} -g laradock -m laradock -G docker_env && \ usermod -p "*" laradock -s /bin/bash 这段配置创建了一个非 root 用户 laradock,解决了容器和宿主机之间文件权限问题: ...

November 9, 2022 · 6 min · 1220 words · Me, LLM

Git Code Snippet

建立独立的分支 当想在项目中使用一个独立分支进行项目文档的管理时,或者当我们想要发布一个软件的开源版本但又不希望将软件的版本历史暴露给外界时,都可以使用以下的方法建立一个独立分支: git help checkout # git checkout --orphan <new-branch> <start-point> 修改提交时间 # 指定本次提交时间 git commit -m "fix..." --date=`date -R` git commit -m "fix..." --date="$(date -R)" git commit -m "fix..." --date="Tue, 11 Jun 2019 17:50:50 +0800" # 修改上次提交时间 git commit --amend --date=`date -R` # 风险操作。会修改 history hash. 忽略文件权限修改 # Git 默认会记录文件权限的修改,可关闭 git config core.filemode false git status 中文文件名乱码 git config --global core.quotepath false 当 core.quotepath 设置为 false 时,Git 将不会对路径名进行 quoting,这意味着路径名中的特殊字符将不被转义。 Git 中文显示问题解决 工作区中删除未跟踪的文件 # 查看文档 git help clean git clean -h # git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] [<pathspec>...] # 【查看】有哪些文件将被删除 git clean -n # 【查看】删除 Git【忽略】的文件与文件夹 git clean -Xn # 【查看】删除【src 路径下】下的【未跟踪】文件以及文件夹 git clean -d -- src # 如果想执行删除 -n 替换为 -f,注意风险。 Git 清除未跟踪文件 | github.io ...

October 1, 2022 · 1 min · 173 words · Me

MySQL 实战 45 讲 Part2

MySQL 实战 45 讲 | 林晓斌

September 14, 2022 · 1 min · 6 words · Me