PHP、Go、JavaScript (ES6+) 核心语法全景对照指南。
第一部分:变量声明与基础数据类型
三种语言在变量作用域、类型检查机制上有着本质区别:
- PHP:弱类型(但 PHP 7/8 引入了强类型声明),变量以
$开头,作用域通常在函数内。 - Go:静态强类型,编译型语言,严格区分类型,支持类型推导
:=,包级作用域与块级作用域。 - JavaScript:弱类型,动态脚本语言,推荐使用
let和const实现块级作用域。
1. PHP 实现
<?php
declare(strict_types=1); // 开启严格类型模式
// 1. 变量与常量声明
$username = "Alice"; // 字符串
$age = 25; // 整型
$balance = 100.50; // 浮点型
$isActive = true; // 布尔型
$data = null; // 空值
// 常量
define('MAX_LOGIN_ATTEMPTS', 5);
const APP_VERSION = "1.0.0";
// 2. 字符串操作
$greeting = "Hello, $username!"; // 双引号支持变量解析
$concat = 'Age: ' . $age; // 单引号不支持解析,使用 . 拼接
// 3. 类型声明 (PHP 7.4+)
function printUserInfo(string $name, int $age, ?float $bal): void {
echo "User: {$name}, Age: {$age}, Balance: " . ($bal ?? 0.0) . "\n";
}
printUserInfo($username, $age, $balance);
2. Go 实现
package main
import "fmt"
// 1. 包级变量与常量声明
const MaxLoginAttempts int = 5
const AppVersion = "1.0.0" // 无类型常量,根据上下文推导
var globalConfig string = "default"
func variablesDemo() {
// 2. 局部变量声明
var username string = "Alice"
var age int = 25
var balance float64 = 100.50
var isActive bool = true
// 短变量声明 (仅限函数内部)
data := "Some Data" // 自动推导为 string
// Go 中没有 null,只有各类型的零值 (nil 适用于指针、切片、映射、接口等)
var ptr *int = nil
// 3. 字符串操作
// Go 字符串不可变,支持双引号和反引号(多行)
greeting := fmt.Sprintf("Hello, %s!", username)
concat := "Age: " + fmt.Sprint(age)
printUserInfo(username, age, balance)
fmt.Println(greeting, concat, isActive, data, ptr)
}
// 4. 函数参数严格定型
func printUserInfo(name string, age int, bal float64) {
fmt.Printf("User: %s, Age: %d, Balance: %.2f\n", name, age, bal)
}
3. JavaScript 实现
// 1. 变量与常量声明 (ES6+)
const MAX_LOGIN_ATTEMPTS = 5; // 常量,不可重新赋值
const APP_VERSION = "1.0.0";
let username = "Alice"; // 块级作用域变量
let age = 25; // Number 类型 (JS 中不区分整型和浮点型)
let balance = 100.50; // Number 类型
let isActive = true; // Boolean
let data = null; // Null 类型
let notDefined; // Undefined 类型
// 2. 字符串操作
// 模板字符串 (Template Literals),支持多行和表达式插值
let greeting = `Hello, ${username}!`;
let concat = 'Age: ' + age;
// 3. 弱类型函数 (可以使用 TypeScript 增加强类型)
function printUserInfo(name, age, bal) {
// 使用 nullish coalescing operator (??) 赋默认值
console.log(`User: ${name}, Age: ${age}, Balance: ${bal ?? 0.0}`);
}
printUserInfo(username, age, balance);
第二部分:复合数据结构(数组、字典、切片)
- PHP:天下无敌的
Array(实际上是有序哈希表),既当列表又当字典。 - Go:严格区分
Array(定长)、Slice(动态切片)和Map(哈希表)。 - JavaScript:区分
Array(动态列表)和Object/Map(键值对)。
1. PHP 的万能数组
<?php
// 1. 索引数组 (List)
$fruits = ["Apple", "Banana", "Orange"];
$fruits[] = "Mango"; // 追加元素
array_push($fruits, "Grape");
// 2. 关联数组 (Map/Dictionary)
$user = [
"id" => 101,
"username" => "bob_smith",
"email" => "bob@example.com",
"roles" => ["admin", "editor"] // 嵌套数组
];
// 添加/修改键值对
$user["status"] = "active";
// 3. 数组遍历
foreach ($user as $key => $value) {
if (is_array($value)) {
echo "$key: " . implode(", ", $value) . "\n";
} else {
echo "$key: $value\n";
}
}
// 4. 常用数组操作
$keys = array_keys($user);
$hasEmail = array_key_exists("email", $user);
$filtered = array_filter($fruits, fn($f) => strlen($f) > 5); // 闭包过滤
2. Go 的 Slice 与 Map
package main
import (
"fmt"
"strings"
)
func dataStructuresDemo() {
// 1. 数组 (Array) - 长度固定,较少直接使用
var arr [3]string = [3]string{"Apple", "Banana", "Orange"}
// 2. 切片 (Slice) - 动态数组,最常用
fruits := []string{"Apple", "Banana", "Orange"}
fruits = append(fruits, "Mango", "Grape") // 追加元素
// 3. 映射 (Map) - 键值对,必须使用 make 初始化或字面量初始化
user := map[string]interface{}{ // 使用 interface{} 支持不同类型的值
"id": 101,
"username": "bob_smith",
"email": "bob@example.com",
"roles": []string{"admin", "editor"},
}
// 添加/修改键值对
user["status"] = "active"
// 4. 遍历
for key, value := range user {
// 类型断言 (Type Assertion)
if roles, ok := value.([]string); ok {
fmt.Printf("%s: %s\n", key, strings.Join(roles, ", "))
} else {
fmt.Printf("%s: %v\n", key, value)
}
}
// 5. 检查键是否存在
email, exists := user["email"]
if exists {
fmt.Println("Email found:", email)
}
}
3. JavaScript 的 Array 与 Object
// 1. 数组 (Array)
const fruits = ["Apple", "Banana", "Orange"];
fruits.push("Mango", "Grape"); // 追加元素
// 2. 对象 (Object) - 作为字典使用
const user = {
id: 101,
username: "bob_smith",
email: "bob@example.com",
roles: ["admin", "editor"]
};
// 添加/修改键值对
user.status = "active";
user["last_login"] = "2023-10-01";
// 3. 遍历对象
for (const [key, value] of Object.entries(user)) {
if (Array.isArray(value)) {
console.log(`${key}: ${value.join(", ")}`);
} else {
console.log(`${key}: ${value}`);
}
}
// 4. 常用高级操作 (ES6 数组方法)
const keys = Object.keys(user);
const hasEmail = "email" in user;
// 链式调用
const longFruits = fruits
.filter(f => f.length > 5)
.map(f => f.toUpperCase());
第三部分:函数、闭包与高阶特性
1. PHP 函数特性
<?php
// 1. 默认参数与可变参数
function buildQuery(string $table, array $conditions = [], string ...$fields): string {
$select = empty($fields) ? "*" : implode(", ", $fields);
$sql = "SELECT {$select} FROM {$table}";
if (!empty($conditions)) {
$sql .= " WHERE " . http_build_query($conditions, '', ' AND ');
}
return $sql;
}
// 2. 匿名函数与闭包 (使用 use 关键字引入外部变量)
$multiplier = 3;
$calculate = function (int $number) use ($multiplier): int {
return $number * $multiplier;
};
// 3. 箭头函数 (PHP 7.4+,单行,自动捕获外部变量)
$calculateArrow = fn(int $number) => $number * $multiplier;
// 4. 命名参数 (PHP 8.0+)
$query = buildQuery(
fields: "id", "name",
table: "users",
conditions: ["status" => 1]
);
2. Go 函数特性
package main
import (
"fmt"
"strings"
)
// 1. 多返回值与可变参数
func buildQuery(table string, conditions map[string]interface{}, fields ...string) (string, error) {
if table == "" {
return "", fmt.Errorf("table name cannot be empty")
}
selectFields := "*"
if len(fields) > 0 {
selectFields = strings.Join(fields, ", ")
}
sql := fmt.Sprintf("SELECT %s FROM %s", selectFields, table)
// 省略复杂的 conditions 拼接逻辑...
return sql, nil
}
func functionDemo() {
// 2. 匿名函数与闭包 (自动捕获外部变量,无需类似 PHP 的 use)
multiplier := 3
calculate := func(number int) int {
return number * multiplier
}
fmt.Println(calculate(10)) // 30
// 3. 延迟执行 defer (Go 独有,常用于资源清理)
defer fmt.Println("This runs at the end of functionDemo")
// 4. 处理多返回值
query, err := buildQuery("users", nil, "id", "name")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(query)
}
3. JavaScript 函数特性
// 1. 默认参数与剩余参数 (Rest parameters)
function buildQuery(table, conditions = {}, ...fields) {
const selectFields = fields.length === 0 ? "*" : fields.join(", ");
let sql = `SELECT ${selectFields} FROM ${table}`;
const condKeys = Object.keys(conditions);
if (condKeys.length > 0) {
const where = condKeys.map(k => `${k}=${conditions[k]}`).join(" AND ");
sql += ` WHERE ${where}`;
}
return sql;
}
// 2. 匿名函数赋值
const calculate = function(number) {
return number * multiplier; // 依赖外部作用域变量
};
// 3. 箭头函数 (Arrow Functions, 不绑定自己的 this)
let multiplier = 3;
const calculateArrow = (number) => number * multiplier;
// 4. 解构赋值传参
function processUser({ id, username, roles = [] }) {
console.log(`Processing ${username} (ID: ${id}) with roles: ${roles}`);
}
const userObj = { id: 1, username: "admin", email: "a@a.com" };
processUser(userObj); // 只提取需要的字段
第四部分:面向对象 (OOP) 与结构体
- PHP:经典的基于类的单继承 OOP(Class, Interface, Abstract, Trait)。
- Go:没有 Class 和继承。通过
Struct(结构体)封装数据,通过给结构体绑定方法实现行为,通过Interface(鸭子类型)实现多态,通过结构体嵌套实现组合。 - JavaScript:基于原型链(Prototype)。ES6 引入了
class语法糖。
1. PHP 的经典 OOP
<?php
// 接口定义契约
interface LoggerInterface {
public function log(string $message): void;
}
// Trait 代码复用机制
trait TimestampTrait {
protected function getTimestamp(): string {
return date('Y-m-d H:i:s');
}
}
// 抽象类
abstract class BaseService {
protected LoggerInterface $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
abstract public function execute(): bool;
}
// 具体实现类
class PaymentService extends BaseService {
use TimestampTrait;
// PHP 8.0 构造器属性提升
public function __construct(
LoggerInterface $logger,
private float $amount
) {
parent::__construct($logger);
}
public function execute(): bool {
$time = $this->getTimestamp();
$this->logger->log("[{$time}] Processing payment of {$this->amount}");
return true;
}
}
// 匿名类实现接口
$consoleLogger = new class implements LoggerInterface {
public function log(string $message): void {
echo "CONSOLE: $message\n";
}
};
$service = new PaymentService($consoleLogger, 99.99);
$service->execute();
2. Go 的结构体与接口 (组合与鸭子类型)
package main
import (
"fmt"
"time"
)
// 1. 接口定义 (Go 的接口是隐式实现的)
type Logger interface {
Log(message string)
}
// 2. 结构体 (代替类)
type ConsoleLogger struct {
Prefix string
}
// 3. 为结构体绑定方法 (实现 Logger 接口)
// 只要实现了 Log 方法,它就是 Logger
func (c *ConsoleLogger) Log(message string) {
fmt.Printf("%s: %s\n", c.Prefix, message)
}
// 4. 基础服务结构体
type BaseService struct {
logger Logger // 依赖注入
}
// 5. 具体服务结构体 (通过嵌套实现类似继承的"组合")
type PaymentService struct {
BaseService // 匿名嵌套,继承了 BaseService 的字段
Amount float64
}
// 为 PaymentService 定义方法
func (p *PaymentService) Execute() bool {
timestamp := time.Now().Format("2006-01-02 15:04:05")
msg := fmt.Sprintf("[%s] Processing payment of %.2f", timestamp, p.Amount)
// 调用嵌套结构体中的 logger
p.logger.Log(msg)
return true
}
func oopDemo() {
logger := &ConsoleLogger{Prefix: "SYS_LOG"}
service := &PaymentService{
BaseService: BaseService{logger: logger},
Amount: 99.99,
}
service.Execute()
}
3. JavaScript 的 Class 语法糖
// JS 没有内置的 Interface,通常靠文档或 TypeScript 约束
// 1. 定义类
class BaseService {
// 私有字段 (ES2022+)
#logger;
constructor(logger) {
this.#logger = logger;
}
// Getter
get logger() {
return this.#logger;
}
// 抛出错误模拟抽象方法
execute() {
throw new Error("Method 'execute()' must be implemented.");
}
}
// 2. 继承
class PaymentService extends BaseService {
#amount;
constructor(logger, amount) {
super(logger); // 必须调用 super
this.#amount = amount;
}
// 私有方法
#getTimestamp() {
return new Date().toISOString();
}
// 方法重写
execute() {
const time = this.#getTimestamp();
this.logger.log(`[${time}] Processing payment of ${this.#amount}`);
return true;
}
}
// 3. 对象字面量实现依赖 (鸭子类型)
const consoleLogger = {
log: function(message) {
console.log(`CONSOLE: ${message}`);
}
};
const service = new PaymentService(consoleLogger, 99.99);
service.execute();
第五部分:错误与异常处理
1. PHP (Try-Catch)
<?php
class CustomDatabaseException extends Exception {}
function connectDB(string $host) {
if (empty($host)) {
// 抛出异常
throw new CustomDatabaseException("Host cannot be empty");
}
// 模拟连接成功
return true;
}
try {
connectDB("");
} catch (CustomDatabaseException $e) {
error_log("DB Error: " . $e->getMessage());
} catch (Exception $e) {
// 捕获其他所有异常
error_log("General Error: " . $e->getMessage());
} finally {
// 无论是否报错都会执行,常用于释放资源
echo "Cleanup resources.\n";
}
2. Go (Error 值返回与 Panic)
Go 不推荐使用类似 try-catch 的控制流,而是将错误作为普通的返回值处理。
package main
import (
"errors"
"fmt"
)
// 定义自定义错误变量
var ErrEmptyHost = errors.New("host cannot be empty")
func connectDB(host string) (bool, error) {
if host == "" {
// 返回错误值
return false, ErrEmptyHost
}
return true, nil
}
func errorDemo() {
success, err := connectDB("")
// 显式检查错误 (Go 的标志性写法)
if err != nil {
// 错误判定 (Go 1.13+)
if errors.Is(err, ErrEmptyHost) {
fmt.Println("DB Error: Provided host is empty.")
} else {
fmt.Println("Unknown Error:", err)
}
return
}
fmt.Println("Connected:", success)
// Go 中的 Panic/Recover 仅用于极其严重的不可恢复错误
// 类似于 try-catch,但不应作为常规业务逻辑
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
// panic("Critical failure!")
}
3. JavaScript (Try-Catch)
class CustomDatabaseError extends Error {
constructor(message) {
super(message);
this.name = "CustomDatabaseError";
}
}
function connectDB(host) {
if (!host) {
throw new CustomDatabaseError("Host cannot be empty");
}
return true;
}
try {
connectDB("");
} catch (error) {
if (error instanceof CustomDatabaseError) {
console.error("DB Error:", error.message);
} else {
console.error("General Error:", error);
}
} finally {
console.log("Cleanup resources.");
}
第六部分:并发与异步处理 (核心差异)
这是三种语言差异最大的地方:
- PHP:传统模型是同步阻塞的(多进程模型,如 PHP-FPM),每次请求一个进程。
- Go:天生为并发设计。使用轻量级的
goroutine和channel进行通信。 - JavaScript:单线程事件循环。使用回调、
Promise、async/await处理非阻塞 I/O。
1. PHP (同步阻塞)
<?php
// PHP 原生核心不支持非阻塞异步(不借助 Swoole/ReactPHP 等扩展)
function fetchData(string $url): string {
sleep(2); // 模拟耗时网络请求,这里会阻塞整个进程
return "Data from $url";
}
echo "Start\n";
$data1 = fetchData("API_1"); // 阻塞 2 秒
$data2 = fetchData("API_2"); // 阻塞 2 秒
echo "End: $data1, $data2\n"; // 总耗时 4 秒
2. Go (Goroutines 与 Channels)
Go 语言可以通过 go 关键字瞬间启动成千上万个并发任务。
package main
import (
"fmt"
"sync"
"time"
)
// 模拟耗时请求
func fetchData(url string, ch chan<- string, wg *sync.WaitGroup) {
defer wg.Done() // 函数结束时通知 WaitGroup 完成
time.Sleep(2 * time.Second) // 模拟耗时
// 将结果发送到通道 Channel
ch <- fmt.Sprintf("Data from %s", url)
}
func concurrencyDemo() {
fmt.Println("Start")
// 创建一个通道用于接收结果
results := make(chan string, 2)
// WaitGroup 用于等待所有 goroutine 完成
var wg sync.WaitGroup
urls := []string{"API_1", "API_2"}
for _, url := range urls {
wg.Add(1)
// 开启 Goroutine 并发执行
go fetchData(url, results, &wg)
}
// 开启一个后台 Goroutine 等待所有任务完成并关闭通道
go func() {
wg.Wait()
close(results)
}()
// 从通道中读取数据(阻塞直到有数据或通道关闭)
for data := range results {
fmt.Println("Received:", data)
}
fmt.Println("End") // 总耗时约 2 秒
}
3. JavaScript (Async / Await 与 Promise)
JS 使用异步非阻塞 I/O,主线程不等待,而是把回调挂起。
// 模拟返回 Promise 的耗时请求
function fetchData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`Data from ${url}`);
}, 2000);
});
}
// 使用 async/await 以同步的代码风格写异步逻辑
async function main() {
console.log("Start");
try {
// 并发执行多个 Promise
const [data1, data2] = await Promise.all([
fetchData("API_1"),
fetchData("API_2")
]);
console.log(`Received: ${data1}`);
console.log(`Received: ${data2}`);
} catch (error) {
console.error("Async Error:", error);
}
console.log("End"); // 总耗时约 2 秒
}
main();
总结
- PHP:围绕 Web 请求生命周期构建,数组操作极其灵活,OOP 体系严谨成熟,适合快速开发传统 Web 后端。
- Go:静态编译,极简语法,舍弃了传统类继承,以强悍的并发能力(Goroutine/Channel)和极高的运行效率见长,适合微服务和云原生架构。
- JavaScript:一处编写到处运行,对象和函数高度灵活,以事件循环和异步非阻塞为核心,全栈(Node.js + 前端)开发的霸主。