news 2026/10/16 4:04:44

PHPWord不用Composer直接生成Word文档:完整代码包与实战避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PHPWord不用Composer直接生成Word文档:完整代码包与实战避坑指南

简介:这是一份开箱即用的PHPWord完整代码包,面向需要在服务端生成或处理Word文档的PHP开发者。PHPWord是纯PHP编写的Office文档操作库,服务器无需安装Microsoft Word即可创建、编辑和读取.docx文件;压缩包同时内置全部依赖与示例,不借助Composer也能直接运行。整个资源约149.1MB,以核心库源码、示例代码和配置说明文档为主,并附带许可协议与入门指南,便于后续集成与二次开发。目前已有1052人浏览学习,适合传统PHP部署环境或希望快速上手的开发者。对照示例运行后,可快速掌握生成段落、表格、页眉页脚并输出docx文件的完整流程。

1. PHPWord 不用 Composer 也能跑:这份完整代码包到底解决什么问题

很多 PHP 开发者第一次接触 PhpWord(PhpOffice 系列里的 Word 文档处理组件)时,第一反应是“先装个 Composer 再说”。但实际接手的生产环境经常不联网、内网隔离,或者项目历史包袱太重,不想引入包管理器。这份“phpword完整代码包含sample无需安装可直接运行”的资源,就是把 PhpWord 的源码和示例脚本一起打包,让开发者在 Apache/Nginx + PHP 环境下直接 require 就能生成 .docx 文件。它解决的是从“没头绪”到“一分钟跑出第一个文档”的问题,适合正在做报表导出、合同生成、批量证书打印的 PHP 从业者,也适合那些只想看代码、不想理解依赖关系的快速验证场景。

2. 先搞清 PhpWord 的加载方式:为什么“无需安装”不是玄学

2.1 PhpWord 的两种引入姿势:Composer 自动加载 vs 手动 require

先用一句话兜底:PhpWord 本质上是一堆按命名空间组织的 PHP 类文件,Composer 只是帮你做了自动加载罢了。所谓“无需安装”,指的是包里已经把这个自动加载器的替代版带了进来,你不用执行composer install命令,只要 include 一个入口文件,注册一下自动加载规则就能正常使用。

常见做法是:

<?php require_once __DIR__ . '/phpword/src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\IOFactory;

这段代码的重点是第一步。PhpWord 自带的Autoloader::register()会调用 PHP 的spl_autoload_register,把PhpOffice\PhpWord\这个命名空间直接映射到包内的src/PhpWord目录,因此后续new PhpWord()时不需要再写一堆require_once。路径参数建议写成绝对路径,尤其是你在 subdir 里跑脚本时,__DIR__能避免很多看不懂的 include 失败。

有人会问:直接从 Composer vendor 目录里复制一份出来,和手写这份 require 有区别吗?有。Composer 生成的vendor/autoload.php会把所有依赖包一次性注册进来,其中可能包含 PhpWord 依赖的其他组件。而手动包只保留 PhpWord 自身,好处是干净、可控、体积小,坏处是你得自己保证环境扩展齐全。如果你拿到的是从 Composer 仓库导出的完整包,入口文件位置可能会在vendor/autoload.php而不是src/PhpWord/Autoloader.php,那是另一种结构,处理方式不同:优先选src入口,找不到时再看 vendor 结构。

我碰到过很多人把Autoloader.php改成自己的文件名移动到了别处,结果类加载失败。除非你清楚自动加载机制,否则不要轻易改包内目录结构,省下的空间最后都会变成排查时间。

2.2 手动引入时的目录结构:你必须保住的三个核心目录

拿到一个号称“无需安装”的 phpword 包,别急着运行,先看目录。一个可用的手动包至少要有这三个部分:

目录/文件作用丢了会怎样
src/PhpWord/核心类与自动加载入口直接白屏,类找不到
templates/模板文件存放目录用模板功能时报文件不存在
samples/示例脚本少了参考,学习成本高

一些打包者还会把vendor/一起塞进来,那通常是为了兼容原来的 Composer 结构。我一般会优先选择只用src的那一版,因为它更干净,也更容易看出引入关系。如果你在手动 require 时报出Class 'PhpOffice\PhpWord\PhpWord' not found,八成是src目录被拆掉或者路径写错,先检查目录树而不是改代码。

这里有一个容易被忽略的边界:PhpWord 的核心代码不依赖第三方包,但它依赖 PHP 的扩展。生成 docx 需要zip扩展(用于打包),处理图片需要 GD 或 Imagick,读取模板需要xml解析能力。也就是说“无需安装”指的是不用安装额外 PHP 类库,不是说你服务器扩展不用管。拿到代码包后,先跑一遍php -m看看有没有zip、gd、xml,缺哪个补哪个,否则脚本跑起来会报“Class 'ZipArchive' not found”之类的错。

2.3 快速验证环境:一个 5 行脚本测出能否生成 docx

在跑任何 sample 之前,先写一个最小脚本验证 PHP 环境与包是否完整。新建check.php,内容如下:

<?php require_once __DIR__ . '/phpword/src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $section->addText('hello phpword'); $writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); $writer->save(__DIR__ . '/check_output.docx'); echo 'ok';

这段代码做的事情很简单:注册自动加载,新建一个空白文档对象,添加一节,节里塞一行文本,最后用Word2007格式写出。如果你能看到ok,并且目录里出现check_output.docx,说明核心链路已经通了。addSection()相当于 Word 里的页面节,每份文档至少一节;addText()是写入段落文本;createWriter($phpWord, 'Word2007')决定输出格式,参数写反了或者大小写不一致也会报错。

用命令行跑就用php check.php,用浏览器跑就直接访问,两者都能输出。差别在于:浏览器环境如果脚本开始前有 HTML 输出,或者保存路径不可写,错误信息容易混在一起;命令行环境输出更干净,所以推荐优先用命令行验证。跑出check_output.docx后,可以用压缩软件打开它,看到word/document.xml就说明这条链路是完整的。如果连ok都没输出来,先把错误显示打开,在文件开头加上ini_set('display_errors', 1); error_reporting(E_ALL);,很多“白屏死机”其实是 fatal error 被隐藏了。

3. 跑通第一个 sample:从空白文档到带表格的 Word 文件

3.1 sample 目录里都有什么:按场景挑你要的示例

PhpWord 的 samples 目录在完整包里通常是一堆Sample_xx_xxx.php命名的脚本,按数字从小到大演示不同能力。最值得优先看的是几个固定场景:纯文本输出、表格、页眉页脚、模板替换、图片插入、列表和样式。你不需要全部读一遍,按目标挑即可。

你的业务目标优先参考的示例类型参考重点
导出单页报告纯文本 + 段落样式字体、缩进、行距
批量打印表表格示例单元格宽度、边框、合并
套用已有合同模板模板替换示例setValue 的用法
生成带抬头标语的文档页眉页脚示例addHeader/addFooter 的写法

拿到包的第一步,我会直接在命令行运行一个最简单的 sample:php samples/xxx.php。如果是浏览器环境,也可以配置一个本地站点访问。即便不做任何修改,先跑通它也能确认这个包在当前 PHP 版本上没有语法兼容问题。运行 sample 时如果提示某个函数不存在,先看自己的 PHP 版本是不是过低,PhpWord 对 PHP 版本有一定要求,这是第一个要注意的边界。

很多人误以为 sample 只是给新手看的,生产代码用不上。其实不是,sample 里藏着很多日常记不住的 API 组合,比如如何设置页边距、如何插入分页符、如何添加超链接。写业务代码前先跑一遍同名功能的 sample,能省掉大量查文档的时间。而且 sample 本身是完整的 PHP 文件,你可以直接复制出来改路径用,这就是它最大的价值。

3.2 复现最常用的生成流程:文字、段落、页眉页脚

下面这段代码是我经常在项目里用来做内部报告生成的骨架,比 hello world 多了页眉、标题样式和多段排版:

<?php require_once __DIR__ . '/phpword/src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); use PhpOffice\PhpWord\PhpWord; $phpWord = new PhpWord(); // 注册标题样式:标题1,加粗,16号 $phpWord->addTitleStyle(1, ['bold' => true, 'size' => 16]); // 添加页面节 $section = $phpWord->addSection([ 'orientation' => 'portrait', 'marginLeft' => 1000, 'marginRight' => 1000, ]); // 页眉和页脚 $header = $section->addHeader(); $header->addText('内部资料 请勿外传', ['size' => 9, 'color' => '888888']); $footer = $section->addFooter(); $footer->addText('第 {PAGE} 页 / 共 {NUMPAGES} 页', ['size' => 9]); // 标题与正文 $section->addTitle('季度运营报告', 1); $section->addText('这是第一段正文内容,用于说明某项目的运行情况和关键指标。', ['size' => 12]); $section->addTextBreak(1); $section->addText('第二段可以分两行,写法是', ['size' => 12]);

这段代码里,addTitleStyle(1, ...)必须先于addTitle()调用,否则样式可能落到默认值上。addSection()的数组参数是节属性,marginLeft/Right以 twip 为单位,1000 twip 大约是 1.27 厘米。页眉/页脚里的{PAGE}和{NUMPAGES}是 Word 域代码,PhpWord 会原样写进文档,Word 打开时自动计算页码,所以你不用自己算第几页。addTextBreak(1)是空一行,不要和addText('')弄混,后者会生成一个空段落而不是视觉空行。

如果你想让正文对齐或缩进,可以在addText的样式数组里加alignment和indentation。比如['align' => 'both', 'indentation' => ['left' => 100, 'right' => 100]]。这里的indentation单位同样是 twip,段落左缩进两个字符,直接可以换算成 100 twip 左右,实际需要微调。这类参数在 sample 里都有呈现,但自己敲一遍才能理解它们之间的关系:字体样式作用于 run,段落样式作用于 paragraph,不要混在同一个数组里。

3.3 表格与样式设置:让输出不再像纯文本堆砌

光有文本的文档太单调,业务系统里真正高频的是表格。PhpWord 的表格对象是逐行逐格构建的,没有 Excel 那种“先画表再填数”的概念。一个两行两列的简单表格长这样:

$table = $section->addTable([ 'borderSize' => 6, 'borderColor' => '333333', 'cellMargin' => 50, ]); $table->addRow(400); // 行高 400 twip $table->addCell(2500)->addText('姓名'); $table->addCell(2500)->addText('分数'); $table->addRow(400); $table->addCell(2500)->addText('A同学'); $table->addCell(2500)->addText('92');

addTable()的数组是整表样式,borderSize代表边框厚度,单位是 eighths of a point,6 大约对应 0.75 磅。borderColor用六位十六进制色值,不要带#。addRow(400)里的数字是行高,addCell(2500)是单元格宽度,同样以 twip 为单位,默认表格总宽度会被 Word 自动撑开。如果边框线始终显示不出来,检查是不是漏了borderSize,PhpWord 默认表格是无线框的。

表格样式最坑的地方在于单元格宽度。很多新手以为addCell(2500)是像素,其实 2500 twip 大约是 4.4 厘米,两个格子合起来才 8.8 厘米,离 A4 页宽还有很大距离。我在做证书打印时吃过这个亏,所有格子宽度写成一样的,结果表格缩在页面一角。后来学到一个规律:总宽度不要超过页面可用宽度,A4 纵向页边距各 1000 twip 时,可用宽度约 8500 twip,表格宽度就按 8000 左右去分配,留点余量。

合并单元格也是常见需求,写法比想象中啰嗦一些。要先getCell()拿到单元格对象,再调setGridSpan把横向合并的列数告诉它:

$row = $table->addRow(); $cell = $row->addCell(4000); $cell->getStyle()->setGridSpan(2); $cell->addText('合并后的单元格');

这里的setGridSpan(2)表示这个单元格横跨两列,后续行里的单元格数量会变得不同,这是 Word 表格的正常结构。合并行方向则更复杂,需要调setVMerge,在纵向合并的第一行标'restart',后续行标'continue',跑 sample 时看到这两个词先不要慌,它就是 Word 里的“垂直合并”。

4. 把数据导进 Word:模板替换与动态内容填充的常见做法

4.1 模板变量写法:${xxx} 与模板文件的关系

报表项目里最常用的不是从零生成,而是拿一个已经排版好的 Word 模板填数据。PhpWord 提供了独立的TemplateProcessor类,它的工作方式有点像数据合并:先在.docx里占位,执行时再把值替换进去。

模板变量默认写法是${变量名},注意外面的花括号是占位符的一部分。在 PHP 里使用它的典型代码:

<?php require_once __DIR__ . '/phpword/src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); use PhpOffice\PhpWord\TemplateProcessor; $template = new TemplateProcessor(__DIR__ . '/templates/contract_template.docx'); $template->setValue('clientName', '某软件公司'); $template->setValue('amount', '10000.00'); $template->setValue('deadline', '2025-06-30'); $template->saveAs(__DIR__ . '/output_contract.docx');

这套流程的关键是:模板必须是真实的 Word 文件,并且文档里必须原样写着${clientName}、${amount}这些占位符。setValue()第一个参数是占位符名字,不需要带${},第二个参数是替换内容。如果替换后的文本里包含了&、<、>这些特殊字符,TemplateProcessor在部分版本里不会自动转义,容易导致 XML 解析失败或文档损坏。这是一个很隐蔽的坑:来源系统里的公司名如果带“ & Co.”,直接写进去后 Word 就报错。我一般会加一层htmlspecialchars($value, ENT_XML1)或者是手动把&替换成&amp;,再传进去,这叫“后手保护”,省得每次提心吊胆。

占位符在 Word 里看起来是一个整体,但实际在底层 XML 里可能是被拆开的。比如你在 Word 界面中打了一个${clientName},Word 自动给每个字符套了样式 run,那么真实存储时可能分成三段,TemplateProcessor的正则可能匹配失败。解决方式很简单:在 Word 里把占位符选中,清除格式后再设置一种统一字体,让它落在一个 run 里。

4.2 批量生成多份文档:循环里跑 PHPWord 的注意点

批量导出是业务里的高频场景,比如一批合同、一批成绩单。很多初学者会这样写:

$template = new TemplateProcessor('template.docx'); foreach ($rows as $row) { $template->setValue('name', $row['name']); $template->saveAs("output_{$row['id']}.docx"); }

这个写法第一轮跑完,第二轮setValue是在上一轮替换后的对象上继续操作,不会自动重置。更稳妥的写法是每次循环都重新读取模板文件:

foreach ($rows as $row) { $template = new TemplateProcessor(__DIR__ . '/templates/contract_template.docx'); $template->setValue('name', $row['name']); $template->setValue('amount', $row['amount']); $template->saveAs(__DIR__ . "/output_{$row['id']}.docx"); unset($template); }

注意这个模式里,new TemplateProcessor每次都会重新解析一遍模板,性能上会有可见开销,但换来了状态隔离。如果你处理的是几千份文档,更合适的做法是先把memory_limit调高,比如ini_set('memory_limit', '512M'),再考虑把模板文件复制到临时目录再替换,避免并发写同一个模板文件。unset($template)是经验之谈,它让对象引用计数归零,防止大批量循环把内存堆爆。

如果数据里有列表(一行数据对应表格里多行),TemplateProcessor还有一个cloneRow方法,它专门用来复制模板里的行。用法是先给表格中要循环的行设置一个占位符,比如${itemName},调用$template->cloneRow('itemName', count($items)),然后从第 1 行开始给每一行 setValue。注意 cloneRow 之后的索引是从 1 开始的,容易和数组下标搞混,跑 example 时仔细看输出。这个方法在生产环境里非常实用,但也是最容易翻车的地方,因为模板行位置不对、占位符不在同一行,都会导致行复制数量偏差。

4.3 输出格式不只是 docx:PDF、HTML 转换的条件限制

PhpWord 的IOFactory::createWriter支持多种格式,不只Word2007。常见的包括:

格式标识对应能力额外依赖
Word2007.docx,最常用无
ODText.odt,LibreOffice 兼容无
HTML.html,简单网页无
PDF.pdf,直接生成 PDF需要额外安装 PDF 库
RTF.rtf,老版兼容无

“无需安装”包一般只保证前三种能直接跑。PDF 输出为什么经常报错?因为createWriter($phpWord, 'PDF')内部会去找一个具体的 PDF 渲染类,比如 Dompdf 或 TCPDF,而这些类不在 phpword 包里。你手动 require 的时候没有它们,自然就失败。我不建议在没有依赖管理的内网里硬上 PDF,优先让 PHP 生成 docx,再让办公软件或转换服务来转 PDF,这样职责更清晰。

HTML 输出则有自己的脾气:PhpWord生成的 HTML 不是完整页面,而是片段。如果你拿它当整页 HTML 用,样式会缺背景和 body 标签。生成 HTML 格式时,我们一般会自己再包一层<html><head><meta charset="utf-8"></head><body>...</body></html>,这样浏览器打开才不会乱码。测试时注意 PhpWord 对样式还原度有限,字体、间距、页眉页脚在 HTML 输出里基本不支持,别期望太高。

5. PHPWord 避坑与排查:五个高频率翻车现场

5.1 现象:生成的 docx 打不开,提示文件损坏

  • 现象:脚本成功输出了ok,.docx文件也在磁盘上,双击却提示“文件已损坏”。
  • 原因:多半是$writer->save()之前就已经有内容输出到了浏览器。PHPecho或 BOM 头混入文件流,破坏了 zip 文件结构;另一种可能是拿去开的文件其实是个空文件,比如路径权限不足导致写入失败。
  • 解决:检查脚本开头有没有<?php前的空格或 BOM,把echo 'ok'放到save()之后。然后确保输出目录可写,可以用chmod 755或is_writable()先判断。最后用file_get_contents读前两个字节,如果是PK就说明是正常 zip 开头。

5.2 现象:中文乱码或字体不对

  • 现象:文档打开后英文字体正常,中文全部变成宋体或者显示方块。
  • 原因:PhpWord 把字体设置直接写进样式,如果段落样式只指定了英文字体名,中文字体由 Word 自动匹配。有些模板里字体缺失,就会回退。
  • 解决:在addText样式中把name设为中文字体名字,比如['name' => 'SimSun', 'size' => 12],同时设置hint为'eastAsia'。另外,模板替换内容时,占位符所在段落的中文字体已经固定,替换后不会重新套用新字体,这是 Word 机制,不是 PhpWord 出 bug。

5.3 现象:内存溢出(PHP Fatal error: Allowed memory size)

  • 现象:文档图片多,或者循环生成几百个文件时,进程直接崩了,日志里出现Allowed memory size of ... exhausted。
  • 原因:TemplateProcessor每次new都会把模板读进内存并创建 DOM 树,大图也会被 base64 处理。循环中如果没释放引用,内存只涨不跌。
  • 解决:循环末尾unset($template),再配合gc_collect_cycles()显式回收。单次生成超大文档时,把memory_limit设成512M或更高,不要盲目迷信 PhpWord 省内存,它本来就是内存密集型的。

5.4 现象:图片无法显示或路径错误

  • 现象:图片位置出现红叉,或者生成时报“file not found”,但确认路径存在。
  • 原因:PhpWord 添加图片通常用$section->addImage($path),它要求路径是能被 PHP 文件函数直接访问的本地路径。相对路径在当前工作目录不对时很容易翻车。
  • 解决:先realpath()拿到绝对路径再传进去。图片格式尽量用 jpg/png/gif,不要传 svg,PhpWord 原生支持的图片能力和旧版 Word 绑定,颜色空间太复杂的 CMYK jpg 也可能导致渲染异常。

5.5 现象:模板变量没替换成功,花括号残留在文档里

  • 现象:输出文档里依然有${name}这样的字面内容,数据没进去。
  • 原因:模板占位符看起来一样,但实际上可能混入了全角花括号,或者在 Word 中被拆成了多个 XML 片段,导致正则匹配失败。
  • 解决:检查模板里占位符是半角${}还是全角,统一替换。如果是从 PDF 或网页复制到 Word 的占位符,最干净的办法是在 Word 里重新敲一遍。另外,占位符如果跨了多个字体 run,TemplateProcessor也可能匹配不上,这种情况把占位符选中后清除格式重新打一次。

6. 从 sample 到生产环境:验证输出并把脚本嵌进既有项目

6.1 用一个校验清单确认输出文档可用

每次生成完文档,我习惯做三步验证。第一步是检查文件头,用 PHP 的 ZipArchive 打开看看是否真的是 zip 格式;第二步是解压后读word/document.xml,确认关键文字出现在 XML 里;第三步才是直接丢给 Word 打开。两步脚本可以写进一个verify.php:

$zip = new ZipArchive(); if ($zip->open('output.docx') === true) { $xml = $zip->getFromName('word/document.xml'); if (strpos($xml, '季度运营报告') !== false) { echo 'docx 结构完整,关键内容存在'; } $zip->close(); }

这里ZipArchive是 PHP 扩展,不是 PhpWord 的依赖,生产环境大多默认开启。如果没开扩展,用命令行unzip -t output.docx也能完成完整性检查,但没法比对内容。养成“先验证再交付”的习惯,很大程度上能避免把一堆打不开的文档发给业务。

6.2 把 PHPWord 封装成自己的文档服务类

直接在每个控制器里写new PhpWord会让代码很快失控。我更倾向于把模板处理收口到一个类里,比如MyDocService,只暴露render($alias, $data)一个方法,内部负责模板路径、变量替换和输出目录。这样业务方不用关心 PhpWord 的 API,后续升级包版本也只改一个文件。

class MyDocService { public function render(string $templateAlias, array $data, string $outputName): string { $template = new TemplateProcessor(__DIR__ . '/templates/' . $templateAlias . '.docx'); foreach ($data as $key => $value) { $template->setValue($key, $value); } $outputPath = __DIR__ . '/output/' . $outputName; $template->saveAs($outputPath); return $outputPath; } }

这个方法的核心是把占位符名和数组 key 对应起来,数据层只要保证$data['name']存在。需要注意模板文件名白名单要提前定义好,防止$templateAlias被外部传入目录穿越字符串。我在生产项目里见过因为模板路径拼接不当而读取到任意文件的案例,这属于安全边界,随手加一层过滤能省很多事。

6.3 从 HTTP 响应下载到文件持久化的切换

开发环境里很多人直接把文件输出到浏览器,但生产系统往往需要落盘再异步发送。先save()到临时目录,再通过响应头触发下载是更稳妥的做法:

$tmpFile = tempnam(sys_get_temp_dir(), 'phpword_') . '.docx'; $writer->save($tmpFile); header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document'); header('Content-Disposition: attachment; filename=' . urlencode('report.docx')); header('Content-Length: ' . filesize($tmpFile)); readfile($tmpFile); unlink($tmpFile);

这里tempnam生成的是临时文件路径,手动加.docx后缀是为了让部分浏览器识别类型。Content-Length必须和文件实际大小一致,否则下载中断。记得在readfile之后马上unlink,避免临时目录被撑爆。我自己的项目里有一条硬规矩:任何用 PhpWord 生成的文件,分享给人之前必须用上面那个清单过一遍,然后才把链接发出去。一开始只觉得是流程慢,后来才发现正是这一步挡住了十几类数据问题,从那以后我每次生成完都强制走一遍。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 4:04:12

AI编码代理的机密安全上下文边界:本地过滤与零信任实践

1. 为什么AI编码代理的上下文边界是个要命的问题先抛一个我亲身踩过的坑。去年我给自己搭了一套本地AI编码助手&#xff0c;用来处理一些内部项目的代码补全和重构建议。刚开始跑得挺爽&#xff0c;直到有一次我让它帮我改一个配置文件&#xff0c;它顺手把旁边一个包含数据库连…

作者头像 李华
网站建设 2026/10/16 4:03:43

MATLAB手写K均值聚类:注释详细、可修改样本数据的完整实现

用MATLAB实现K均值聚类&#xff0c;几乎是每个接触机器学习的人都会做的一道基础练习。不过奇怪的是&#xff0c;网上能找到的版本要么注释少得可怜&#xff0c;复制下来只能干瞪眼&#xff1b;要么封装了一大堆高级函数&#xff0c;想改一个参数都得翻半天文档。这半年帮几个做…

作者头像 李华
网站建设 2026/10/16 4:03:16

PostgreSQL赋值全解析:从字段更新到PL/pgSQL变量绑定

很多做应用开发的同事一提到 PostgreSQL 里的“赋值”&#xff0c;第一反应就是UPDATE user SET name 张三。这个理解没错&#xff0c;但只停留在“改字段”的层面。真正进入 PostgreSQL 的开发&#xff08;尤其是写存储过程、函数、触发器、批量数据处理脚本&#xff09;之后…

作者头像 李华
网站建设 2026/10/16 4:03:15

纯C手写GSM PDU短信编解码:嵌入式物联网实战

简介&#xff1a;这是一份面向嵌入式与通信开发者的PDU短信编解码C语言实现demo&#xff0c;聚焦GSM网络中SMSC与手机之间二进制短信传输的底层原理&#xff0c;适合想深入理解短信协议、动手实现编解码逻辑的中级开发者。资源包共13个文件、约618KB&#xff0c;以h头文件与cpp…

作者头像 李华
网站建设 2026/10/16 4:03:13

Cadence Allegro 17.x 降版本到 16.6 的安装配置与避坑指南

简介&#xff1a;这份资源是面向PCB设计工程师的Cadence Allegro版本转换工具&#xff0c;专门解决17.x高版本设计文件无法在16.6低版本环境中打开或编辑的兼容性难题。对于需要与使用旧版Allegro的团队协作、或客户指定交付16.6格式文件的设计者而言&#xff0c;它提供了一条便…

作者头像 李华
网站建设 2026/10/16 4:03:10

PostgreSQL数据库开发中的赋值机制:从SQL到PL/pgSQL的完整指南

1. 从一条UPDATE语句开始理解“赋值”在PG开发里的分量做 PostgreSQL 开发这几年&#xff0c;我越来越觉得“赋值”才是整个数据库应用里最容易被低估的一个动作。很多人觉得赋值不就是“给变量塞个值”吗&#xff1f;SELECT 查出来&#xff0c;写个变量&#xff0c;再插回去&a…

作者头像 李华