资讯动态

Mac 上从零搭建 PHP + MySQL 环境并跑通网页操作数据库

发布时间:2026/10/18 19:07:59 来源:尧图企业网站定制
1. 为什么要在 Mac 上折腾 PHP MySQL 这套组合很多刚接触后端开发的朋友第一个念头往往是“都什么年代了还玩 PHP”但现实情况是大量中小型网站、内部管理系统、老旧项目维护依然跑在 PHP MySQL 这套组合上。尤其是你想快速做一个能读写本地数据库的小网页PHP 的入门门槛低到令人发指——不需要编译不需要复杂依赖写完文件扔到目录里就能跑。Mac 自带 Apache 和 PHP 的历史虽然已经结束新系统移除了内置 PHP但这反而让环境搭建变得更清晰可控。这篇文章要解决的核心问题就一个在 Mac 上从零搭出一套能跑 PHP、能连本地 MySQL、能通过浏览器操作数据库的完整环境并且跑通一个最小可用的例子。适合谁看刚学后端的学生、想自己做个工具站的产品经理、需要维护老项目的运维、以及任何对“网页操作数据库”这件事好奇的开发者。你不需要有 PHP 基础但需要会打开终端、能看懂基本的命令行输出。我见过太多人卡在第一步MySQL 装完了不知道密码怎么设PHP 页面打开一片空白不知道去哪看报错连接数据库时报“Access denied”却不知道改哪个配置。这些坑我都会在下面逐个拆掉。整套流程实测下来从零到跑通大约需要 40 分钟其中大部分时间花在下载和配置上真正写代码的时间不到 10 分钟。2. 环境搭建的整体思路与工具选型2.1 为什么选这套方案而不是 Docker 或集成包在 Mac 上搭 PHP MySQL常见路线有三条一是用 MAMP/XAMPP 这类集成包二是用 Docker 起容器三是手动分别安装。集成包的优点是双击就能用缺点是目录结构固定、版本切换麻烦、出了问题不好排查而且很多集成包自带的 PHP 版本偏旧。Docker 方案最干净隔离性好但对新手来说多了一层网络和卷映射的概念调试时容易懵。我推荐手动安装理由很直接你能清楚知道每个组件装在哪、配置文件在哪、日志在哪。这对后续排查问题是决定性的。手动安装用 Homebrew 管理升级卸载都方便而且 Mac 上 Homebrew 的 PHP 和 MySQL 配方非常成熟基本不会出幺蛾子。唯一需要注意的是 macOS 版本和 Homebrew 的兼容性这个后面会讲。2.2 组件版本选择与依赖关系整套环境涉及三个核心组件PHP处理网页逻辑、MySQL存储数据、Web 服务器。Web 服务器这里有个选择用 Apache 还是 Nginx或者直接用 PHP 内置的开发服务器。对于本地开发和“跑通一个小例子”这个目标我强烈建议用 PHP 内置服务器一条命令就能启动不需要配置虚拟主机、不需要改 hosts 文件。等你需要部署到生产环境时再学 Nginx 配置也不迟。版本方面PHP 选 8.x 系列8.1 或 8.2 都行MySQL 选 8.0。这里有个关键点PHP 连接 MySQL 的扩展在 PHP 7 之后发生了重大变化。老教程里用的mysql_connect()函数在 PHP 7 就被移除了现在必须用mysqli或PDO。如果你照着五年前的教程写代码会直接报“Call to undefined function”。所以版本选新不选旧但代码写法要跟上。组件推荐版本安装方式作用Homebrew最新官方脚本包管理器PHP8.2brew install php处理网页逻辑MySQL8.0brew install mysql数据存储内置服务器PHP 自带php -S本地 Web 服务2.3 安装顺序与依赖处理逻辑安装顺序有讲究先装 Homebrew再装 PHP最后装 MySQL。为什么因为 PHP 的 MySQL 扩展mysqli、pdo_mysql在编译时需要知道 MySQL 的客户端库位置。虽然 Homebrew 的 PHP 配方通常已经内置了这些扩展但先装 MySQL 能让扩展链接更顺畅。另外MySQL 安装后需要初始化数据目录和设置 root 密码这一步如果放在 PHP 之后做不影响 PHP 本身但会影响你测试连接的时间点。还有一个隐藏依赖macOS 的命令行工具Command Line Tools。Homebrew 安装 PHP 时会用到编译工具链如果没装会提示你安装。这个通常在你第一次运行brew install时自动触发跟着提示走就行大概下载 1-2 GB取决于网速。3. 手把手实操从零到跑通第一个页面3.1 Homebrew 安装与常见网络问题处理打开终端粘贴官方安装命令。这里我不贴具体命令了因为官方脚本地址偶尔会变你直接搜“Homebrew 官网”拿最新命令最稳妥。安装过程中会要求输入密码这是正常的因为要写入/usr/local或/opt/homebrew目录。安装完成后运行brew --version验证。如果提示“command not found”大概率是环境变量没配好。Apple Silicon 芯片的 Mac 默认路径是/opt/homebrew/binIntel 芯片是/usr/local/bin。你需要把对应路径加到~/.zshrc文件里。具体操作用文本编辑器打开~/.zshrc加一行export PATH/opt/homebrew/bin:$PATHIntel 芯片改成/usr/local/bin保存后运行source ~/.zshrc生效。提示如果你在国内网络环境下遇到下载慢的问题可以配置 Homebrew 的镜像源。具体方法搜“Homebrew 镜像配置”有很多现成教程这里不展开。但要注意镜像源只加速下载不影响包本身的完整性。3.2 PHP 安装与内置服务器启动验证运行brew install php。这个命令会安装 PHP 以及一系列依赖包括openssl、readline等。安装完成后运行php -v查看版本。如果显示 PHP 8.x说明成功。接下来验证 PHP 能否解析网页。在任意目录下新建一个文件叫info.php内容就一行?php phpinfo(); ?然后在终端进入这个文件所在目录运行php -S localhost:8000你会看到终端输出“PHP 8.x Development Server started”。打开浏览器访问http://localhost:8000/info.php如果看到一个紫色的表格页面里面列出了 PHP 的所有配置信息说明 PHP 环境完全正常。这个phpinfo()页面是排查问题的利器后面连接数据库时如果报错可以在这里搜索“mysqli”或“pdo_mysql”确认扩展是否加载。注意php -S启动的服务器只监听 localhost外部设备访问不了。这是本地开发的安全设计不要试图改成0.0.0.0除非你清楚风险。另外这个服务器是单线程的同时处理多个请求会排队但本地开发完全够用。3.3 MySQL 安装、初始化与 root 密码设置运行brew install mysql。安装完成后MySQL 默认不会自动启动。你需要运行brew services start mysql来启动服务并设置开机自启。如果想手动控制可以用mysql.server start和mysql.server stop。MySQL 8.0 安装后root 用户默认没有密码或者有一个随机生成的临时密码取决于安装方式。Homebrew 安装的 MySQL 通常 root 密码为空。运行mysql -u root如果能直接进入 MySQL 命令行说明密码为空。这时候必须立刻设置密码否则任何本地程序都能无密码连接你的数据库。设置密码的命令ALTER USER rootlocalhost IDENTIFIED BY 你的新密码; FLUSH PRIVILEGES;把“你的新密码”替换成你自己设的密码。设置完成后退出再重新登录验证mysql -u root -p输入新密码能进去就对了。提示MySQL 8.0 默认的认证插件是caching_sha2_password而老版本的 PHP MySQL 扩展可能不支持这个插件。如果你在 PHP 连接时报“Authentication plugin caching_sha2_password cannot be loaded”需要把 root 用户的认证方式改成mysql_native_password。命令是ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;。不过 PHP 8.x 的 mysqli 扩展已经支持新插件通常不需要改。3.4 创建测试数据库和表进入 MySQL 命令行后创建一个用于测试的数据库和一张简单的表。这里我设计一个“用户留言板”的场景表结构简单但足够演示增删改查。CREATE DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE test_db; CREATE TABLE messages ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );这里有几个细节值得说字符集用utf8mb4而不是utf8因为 MySQL 的utf8是残缺的存不了 emoji 和某些生僻字utf8mb4才是真正的 UTF-8。created_at字段用TIMESTAMP并设置默认值为CURRENT_TIMESTAMP这样插入数据时不用手动写时间数据库自动记录。id字段用AUTO_INCREMENT让数据库自动分配主键避免手动管理 ID 冲突。3.5 编写第一个 PHP 连接脚本现在回到 PHP 这边。在之前info.php所在目录新建一个db_test.php文件。内容如下?php $host localhost; $user root; $pass 你的密码; $dbname test_db; $conn new mysqli($host, $user, $pass, $dbname); if ($conn-connect_error) { die(连接失败: . $conn-connect_error); } $conn-set_charset(utf8mb4); $sql INSERT INTO messages (name, content) VALUES (测试用户, 这是第一条留言); if ($conn-query($sql) TRUE) { echo 新记录插入成功ID 为: . $conn-insert_id; } else { echo 插入失败: . $conn-error; } $conn-close(); ?把你的密码替换成你设置的 MySQL root 密码。保存后浏览器访问http://localhost:8000/db_test.php。如果看到“新记录插入成功ID 为: 1”说明 PHP 已经成功连接 MySQL 并写入了数据。这个脚本虽然简单但包含了连接数据库的完整要素主机地址、用户名、密码、数据库名、字符集设置、错误处理、关闭连接。其中set_charset(utf8mb4)这行很多人会漏掉导致中文乱码。connect_error判断是必须的否则连接失败时页面会显示一堆看不懂的警告。3.6 读取数据并渲染成网页插入数据只是第一步真正“网页操作数据库”的核心是读取并展示。新建list.php?php $conn new mysqli(localhost, root, 你的密码, test_db); $conn-set_charset(utf8mb4); $result $conn-query(SELECT * FROM messages ORDER BY created_at DESC); echo h1留言列表/h1; echo table border1 cellpadding10; echo trthID/thth姓名/thth内容/thth时间/th/tr; while ($row $result-fetch_assoc()) { echo tr; echo td . htmlspecialchars($row[id]) . /td; echo td . htmlspecialchars($row[name]) . /td; echo td . htmlspecialchars($row[content]) . /td; echo td . $row[created_at] . /td; echo /tr; } echo /table; $conn-close(); ?访问http://localhost:8000/list.php你会看到一个表格里面显示刚才插入的那条留言。这里用htmlspecialchars()包裹输出内容是为了防止 XSS 攻击——如果有人留言内容里写了script标签不加这个函数就会直接执行脚本。这是安全底线哪怕本地测试也要养成习惯。4. 常见问题与排查技巧实录4.1 连接数据库报错的几种典型情况实际操作中连接数据库这一步是报错重灾区。我把最常见的几种错误和排查路径整理成表方便你对照。错误信息可能原因解决方法Connection refusedMySQL 服务没启动运行brew services start mysqlAccess denied for user密码错误或用户名不对检查密码确认是 rootlocalhostUnknown database数据库名写错或没创建用SHOW DATABASES;确认No such file or directorysocket 路径不对指定127.0.0.1代替localhostCall to undefined functionPHP 扩展没加载检查 phpinfo 里有没有 mysqli其中“No such file or directory”这个错误特别隐蔽。原因是 PHP 连接localhost时默认走 Unix socket 文件而 MySQL 的 socket 文件路径可能和 PHP 预期的不一致。解决办法很简单把连接地址从localhost改成127.0.0.1强制走 TCP 连接。这个技巧我用了无数次几乎百试百灵。4.2 PHP 页面空白或显示源码的排查有时候你访问 PHP 页面浏览器直接显示 PHP 源代码或者一片空白。显示源码说明 Web 服务器没有把 PHP 交给解析器处理——如果你用的是php -S内置服务器这种情况几乎不会发生因为内置服务器本身就是 PHP 进程。但如果用 Apache 或 Nginx就需要检查 PHP 模块是否加载。页面空白则通常是 PHP 报错但错误信息没显示。默认情况下PHP 的错误显示是关闭的。你可以在 PHP 文件开头临时加上ini_set(display_errors, 1); error_reporting(E_ALL);这样所有错误都会直接打印在页面上。排查完记得去掉这两行生产环境绝对不能开。4.3 中文乱码的根源与彻底解决中文乱码是 PHP MySQL 的经典问题根源在三个环节的字符集不一致数据库表的字符集、MySQL 连接的字符集、PHP 输出的字符集。任何一环不是utf8mb4都可能乱码。彻底解决的方案是三层都设对建表时用CHARACTER SET utf8mb4PHP 连接后立刻set_charset(utf8mb4)HTML 输出时加meta charsetutf-8。这三步做到位乱码问题基本绝迹。如果还乱码用SHOW VARIABLES LIKE character%;检查 MySQL 服务端的默认字符集必要时在 MySQL 配置文件里改。提示MySQL 8.0 的默认字符集已经是utf8mb4所以新建数据库时不指定字符集通常也没问题。但显式指定是好习惯尤其是团队协作时避免因为环境差异导致问题。4.4 端口占用与进程管理php -S localhost:8000启动时如果提示“Address already in use”说明 8000 端口被占用了。可能是之前启动的 PHP 服务器没关掉也可能是其他程序在用。查看端口占用的命令lsof -i :8000找到 PID 后kill -9 PID干掉进程或者换个端口比如php -S localhost:8080。MySQL 默认端口是 3306如果被占用MySQL 会启动失败。检查方法类似lsof -i :3306。不过 3306 被占用的概率很低除非你装了多个 MySQL 实例。5. 从示例到实用几个值得马上加的改进5.1 把数据库配置抽离成独立文件上面的示例把数据库密码直接写在 PHP 文件里这在本地测试没问题但一旦代码要分享或部署密码就泄露了。正确的做法是把配置抽到一个单独的文件比如config.php?php define(DB_HOST, 127.0.0.1); define(DB_USER, root); define(DB_PASS, 你的密码); define(DB_NAME, test_db); ?然后在其他文件里require config.php;使用常量。更进一步可以把config.php加入.gitignore再提供一个config.example.php作为模板。这是行业标准做法花两分钟就能改好。5.2 用 PDO 替代 mysqli 的理由PHP 连接 MySQL 有两种主流方式mysqli和PDO。上面的示例用的是mysqli因为它直观、函数名好记。但如果你打算长期写 PHP我建议尽早转向PDO。原因有三PDO 支持多种数据库MySQL、PostgreSQL、SQLite 等换数据库时不用重写连接代码PDO 的预处理语句更安全能彻底杜绝 SQL 注入PDO 的异常处理更现代用 try-catch 捕获错误比判断返回值优雅得多。用 PDO 重写连接部分try { $pdo new PDO(mysql:host127.0.0.1;dbnametest_db;charsetutf8mb4, root, 你的密码); $pdo-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { die(连接失败: . $e-getMessage()); }插入数据时用预处理$stmt $pdo-prepare(INSERT INTO messages (name, content) VALUES (:name, :content)); $stmt-execute([:name 测试用户, :content PDO 插入的内容]);这样即使content里包含 SQL 关键字也不会被当成 SQL 执行。5.3 加一个简单的表单实现真正的“网页操作”目前插入数据是靠写死 SQL 语句不够“网页”。加一个 HTML 表单让用户输入姓名和内容提交后写入数据库这才算完整的交互闭环。新建form.php?php require config.php; $conn new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME); $conn-set_charset(utf8mb4); if ($_SERVER[REQUEST_METHOD] POST) { $name $_POST[name] ?? ; $content $_POST[content] ?? ; if ($name $content) { $stmt $conn-prepare(INSERT INTO messages (name, content) VALUES (?, ?)); $stmt-bind_param(ss, $name, $content); $stmt-execute(); echo p留言成功/p; } } ? form methodpost 姓名input typetext namename requiredbr 内容textarea namecontent required/textareabr button typesubmit提交/button /form a hreflist.php查看所有留言/a这个表单用preparebind_param实现了参数化查询ss表示两个参数都是字符串类型。提交后数据写入数据库点击链接就能看到列表。到这里一个完整的“网页操作本地 MySQL 数据库”的闭环就形成了。5.4 开发时的实时刷新与调试习惯用php -S开发时每次改完 PHP 文件刷新浏览器就能看到效果不需要重启服务器。但如果你改了php.ini配置就需要重启。另外建议在开发时打开错误显示在php.ini里设置display_errors On或者在每个文件开头临时开启。生产环境则相反必须关闭错误显示把错误记录到日志文件。还有一个实用技巧在终端运行php -S localhost:8000时所有请求日志会实时打印在终端里。如果某个请求返回 500 错误终端会显示具体的错误信息比在浏览器里看空白页面高效得多。养成看终端日志的习惯排查效率翻倍。6. 我个人在实际操作中的几点体会这套环境我搭过不下十次每次换新 Mac 或者帮别人配置都要走一遍。最大的感受是Homebrew 的 PHP 和 MySQL 配方已经非常成熟真正花时间的不是安装而是配置和排错。尤其是 MySQL 8.0 的认证插件变化和 PHP 扩展的加载路径这两个点卡住过很多人。另一个体会是不要怕报错怕的是看不到报错。PHP 默认不显示错误MySQL 连接失败也只给一个模糊的提示。所以开发阶段一定要把错误显示打开把日志级别调低让所有问题都暴露出来。等代码稳定了再关掉。这个习惯能帮你省下大量猜测的时间。最后说一个细节php -S内置服务器虽然方便但它不支持.htaccess文件也不支持 URL 重写。如果你后续要学框架比如 Laravel需要换成 Nginx 或 Apache。但那是下一步的事现在先把基础跑通把“网页读写数据库”这个核心逻辑吃透后面的路会顺很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑