Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 339

Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 392

Deprecated: parse_url(): Passing null to parameter #1 ($url) of type string is deprecated in /www/wwwroot/blog_qqvbc_com/usr/plugins/Access/Access_Core.php on line 394
Joyber 的博客

类文件物理存在,但Yii自动加载找不到,高级模板新建独立api应用,99%是缺少 @api 别名,Yii autoload靠别名映射,不是composer psr‑4。

根因说明

Yii2高级模板:

  • @frontend@backendcommon/config/bootstrap.php 预先注册别名。
  • 你手动新建的api应用,没有注册 @api 别名
    当解析 api\controllers\TemplateController
    Yii自动加载逻辑:@api/controllers/TemplateController.php,别名@api不存在 → 直接放弃加载,class_exists返回false,哪怕磁盘上文件真实存在。

修复步骤

1、注册@api别名(必须)

打开 common/config/bootstrap.php,追加一行:

Yii::setAlias('@api', dirname(__DIR__) . '/api');
frontend/backend就是在这里注册别名,api同样需要这里注册,不是写在api/config/main.php里面,main.php的aliases不参与引导阶段自动加载。

2、核对 api/config/main.php

return [
    'id' => 'api',
    'basePath' => dirname(__DIR__),
    // 这里命名空间严格 api\controllers
    'controllerNamespace' => 'api\controllers',
    // 这里不要写 aliases 数组做@api,此处加载时机太晚,autoload阶段还没执行
    // ...其余配置
];

3、验证调试代码,放到 api/web/index.php 最顶部

<?php
// 打印别名路径,看是否指向正确api目录
var_dump(Yii::getAlias('@api'));

$cls = 'api\controllers\TemplateController';
var_dump($cls, class_exists($cls));

// 手动拼装Yii预期的文件路径
$file = Yii::getAlias('@api/controllers/TemplateController.php');
var_dump($file, file_exists($file));

die;
  • Yii::getAlias('@api') 如果抛出异常:别名没注册,就是上面bootstrap漏写。
  • file_exists($file)=true,但是class_exists=false:确认别名生效,Yii自动加载器依然不去include该文件。

4、其他踩坑点

  1. 大小写严格TemplateController.php文件名、类名完全一致;Linux区分大小写,Windows会掩盖问题。
  2. 控制器文件第一行 namespace api\controllers; 末尾分号不能丢。
  3. opcache缓存:修改bootstrap.php后,重启php‑fpm,清除opcache,否则旧别名常驻内存。
  4. 不要用frontend入口访问api,浏览器访问必须是 api/web/index.php

临时快速验证(强制类映射,用来确认问题)

api/config/main.php配置加入,写死类映射,如果访问正常,100%确认是别名/autoload问题:

return [
    // ...
    'classMap' => [
        'api\controllers\TemplateController' => '@api/controllers/TemplateController.php',
        'api\controllers\DefaultController' => '@api/controllers/DefaultController.php',
    ],
];
加上classMap之后访问正常,说明物理文件完全没问题,就是Yii自动加载阶段找不到@api别名。

排查顺序

  1. common/config/bootstrap.php 是否添加 Yii::setAlias('@api',xxx)
  2. 重启php‑fpm,清除opcache
  3. index.php调试代码看Yii::getAlias('@api')输出路径
  4. 确认访问入口是api/web/index.php,不是frontend入口
高级模板独立应用,不是靠composer psr‑4自动加载,是Yii别名机制,很多人踩这个坑,文件放对,忘记注册别名,class_exists直接false。

要将已经由 Git 跟踪的目录加入忽略,必须先从 Git 缓存中移除该目录的追踪状态,再将其写入 .gitignore 文件。执行以下三个步骤即可完成:

操作步骤清除暂存区缓存:
运行命令

 git rm -r --cached 目录名

(注意这只会从 Git 记录中移除,不会删掉你本地电脑里的真实文件夹)。

添加至忽略文件:

打开或创建根目录下的 .gitignore 文件,在里面写上你的目录名字,例如 目录名/。

提交这一改动:运行 git add .gitignore 和 git commit -m "stop tracking 目录名" 把修改保存到仓库中。

.gitignore 格式规则

基础语法

# 这是注释,#开头
# 忽略指定文件
test.log

# 忽略整个目录(末尾带 / 代表文件夹)
node_modules/

# 忽略该目录下所有文件,不忽略目录本身
dist/*

# ! 取反,不忽略(例外),必须写在被忽略规则后面
!dist/index.html

# * 通配任意字符
*.log

# ** 递归匹配多级目录
**/temp.txt     # 所有层级下的 temp.txt
**/build/       # 任意位置 build 文件夹

# ? 匹配单个字符
file?.txt

重要坑点

  1. /xxx 开头斜杠:只匹配仓库根目录,不会递归子目录
    /vendor/ 只忽略根下vendor,子文件夹vendor不会生效
  2. 已经被git追踪过的文件,写.gitignore不会自动取消跟踪,需要手动:

    git rm --cached 文件名
  3. 规则从上往下解析,后面的规则优先级更高;! 要放在屏蔽规则之后。

PHP/Yii2 最简示例模板

# 日志
*.log
runtime/
web/assets/

# IDE
.idea/
.vscode/

# 依赖
vendor/

# 环境配置
.env
config/db-local.php

# os文件
.DS_Store
Thumbs.db

生效位置

  • 仓库根目录 .gitignore 全局生效(最常用)
  • 子文件夹内也可以放 .gitignore,只对当前文件夹及下级生效。

需要我给你一份Yii2项目完整可直接复制的.gitignore吗。

Bash:删除当前目录所有内容,保留 data、.git 两个目录

先预览(务必先跑这条,核对待删除列表)

find . -maxdepth 1 ! -path . ! -path ./data ! -path ./.git

确认输出是你要删掉的文件/文件夹,再执行删除:

find . -maxdepth 1 ! -path . ! -path ./data ! -path ./.git -exec rm -rf {} +

参数说明

  • ! -path .:排除当前目录本身
  • ! -path ./data:保留data文件夹
  • ! -path ./.git:保留.git版本控制目录
  • -maxdepth 1:只操作当前层级,不会钻进data/.git内部删除内容

Windows PowerShell 版本(保留 data 与 .git)

预览:

Get-ChildItem . | Where-Object {$_.Name -notin @('data','.git')}

执行删除:

Get-ChildItem . | Where-Object {$_.Name -notin @('data','.git')} | Remove-Item -Recurse -Force
⚠️操作前建议备份,预览输出确认无误再执行删除命令。

原因

bash 的 * 通配符默认不会匹配 .开头隐藏文件.git.env.gitignore),所以 mv src/* ./ 只会移普通文件,隐藏文件留在src目录里面。

千万不要写 mv src/.* ./.*会匹配 ...,会把当前、上级目录也移动,直接炸锅。

方案1(Bash,最稳妥,推荐,composer临时目录迁移场景)

#开启dotglob,让*包含隐藏文件,不包含 . 和 ..
shopt -s dotglob
mv src/* ./
#关闭dotglob,恢复shell默认行为
shopt -u dotglob

执行完,src里面所有(含.git、.env)全部移动到当前目录。

方案2 不修改shell选项,直接写模式

mv src/* src/.[!.]* ./ 2>/dev/null

2>/dev/null 抑制“没有匹配到隐藏文件”的报错。

方案3 find(跨shell通用,脚本里优先用)

find src -mindepth 1 -maxdepth 1 -exec mv {} ./ \;

‑mindepth 1跳过src本身,所有子项(普通+隐藏)全部移动出来,zsh/bash都兼容,不会踩通配符坑。


你刚才composer场景完整实操示例

composer create-project topthink/think temp_proj
cd temp_proj
#把temp_proj里面全部内容(含.git .env)移动到上一级
shopt -s dotglob
mv * ../
shopt -u dotglob
cd ..
rm -rf temp_proj

校验是否全部迁移完成

ls -la

查看是否存在 .git .env 这类点开头文件。

重要提醒:移动前建议先 ls -la src 预览一遍,确认要移动的文件列表,避免误操作覆盖本地已有文件。

下载地址:
https://github.com/wyf9661/typora-free

打开提示这个怎么办:
image.png

那就用到了一个宝藏软件:runasdate,这里不提供下载连接了
下载这个软件,可以把指定的程序穿越到古代运行,不影响系统时间

打开这个软件选择typora运行文件,设置一下日期到2019年1月1号,点击添加到桌面快捷方式方便下次使用;

使用runasdate后,桌面打开这个程序好用,但是其它.md扩展的文件要想用这种方式打开,选择使用桌面这个快捷方式打开,不管用了,怎么办?

批处理 bat 中转(最简单,不碰注册表,推荐)

  1. 新建文本,改后缀为OpenByRunAsDate.bat

    @echo off
    :: RunAsDate路径,用64位就写RunAsDate64.exe完整路径
    set RA="D:\Tools\RunAsDate\RunAsDate.exe"
    :: 设置虚拟时间 日/月/年 时:分:秒
    set DATETIME=01/01/2025 00:00:00
    :: 你的真实软件路径
    set APP="D:\Soft\Target.exe"
    
    %RA% %DATETIME% %APP% "%~1"

    修改三处路径:RunAsDate 位置、虚拟时间、你的主程序 exe。
    "%~1"接收双击传入的文件路径,不能丢。

保存。右键你的.xxx文件 → 打开方式 → 选择此 bat,勾选始终使用此应用打开。

缺点:会闪一下黑 cmd 窗口。

消除黑窗口:把 bat 编译成 exe
工具如Bat To Exe Converter,编译选项选:不可见应用程序,输出OpenByRunAsDate.exe,之后文件关联直接指向这个编译后的 exe,双击无黑框。

Bat To Exe Converter工具下载链接:
https://github.com/l-urk/Bat-To-Exe-Converter-64-Bit/releases

注意:
Exe‑Format 选32 Bit | Console (Visible)显示窗口,会出现黑框。
改为 Invisible application(不可见)就好了

亲测如果选64bit的,导出为exe提示失败生成不了exe

方案 B(推荐,彻底无黑框,不用 bat2exe 工具,用 VBS 做包装器)
新建文本,后缀改为 RunTypora.vbs

Set objShell = CreateObject("WScript.Shell")
'注意所有路径,引号处理;RunAsDate、时间、Typora、接收传入文件参数
Dim ra, dt, app, arg
ra = """F:\runasdate-x64\RunAsDate.exe"""
dt = "01/01/2019 00:00:00"
app = """F:\Typora\Typora.exe"""

'获取双击传入的文件路径
If WScript.Arguments.Count > 0 Then
    arg = """" & WScript.Arguments(0) & """"
Else
    arg = ""
End If

objShell.Run ra & " " & dt & " " & app & " " & arg, 0, False

,0 = 完全隐藏控制台窗口,不会闪烁。
保存为RunTypora.vbs。
然后:右键你的.md文件 → 打开方式 → 选择这个 vbs 脚本。

vbs 原生无黑窗口,不会闪烁,直接调用 RunAsDate 启动 Typora,接收双击的文件路径参数。
缺点:系统打开方式列表里不会直接显示 vbs,需要 “更多应用 → 在这台电脑上查找其他应用” 选中这个.vbs。

如果想做成 exe(vbs 打包 exe)
用Vbs To Exe工具,输出为 Windows 应用(无控制台),打包出来的 exe,双击 md 文件,零闪烁。

补充排查点
1.RunAsDate 时间格式必须 dd/mm/yyyy,01/01/2019是对的,不要写成2019‑01‑01,时间格式错注入失效。

  1. 全部路径带英文双引号。
    3.Typora 如果需要管理员权限,RunAsDate 也要管理员,否则时间注入无效。

最后最后本人声明:本文仅供个人笔记、备忘之用,仅作参考,倡议有条件的还是去支持一下正版