yii源码分析4——非核心类的导入注册,yii源码_PHP教程
yii源码分析4——非核心类的导入注册,yii源码
转载请注明: TheViper http://www.cnblogs.com/TheViper
在yii源码分析1中说到spl_autoload_register注册给定的函数作为 __autoload 的实现,在这里是autoload().
<span>public</span> <span>static</span> <span>function</span> autoload(<span>$className</span><span>) { </span><span>include</span> self::<span>$_coreClasses</span> [<span>$className</span><span>]; }</span>
实际上这个autoload()是没有考虑非核心文件的引入的。比如,在app文件夹经常会有自定义的一些重要文件夹,比如'application.utils.*(工具类),'application.filters.*'(过滤类),'application.validators.*'(校验类)等。
在实际用的时候,是不用一个一个include的,直接new就可以了,yii已经帮我们做了include的工作。而这个工作就是在autoload()里面做的。
上面的代码很显然没有考虑非核心文件的引入,这是我的疏忽。
那yii是怎么帮我们引入非核心文件的?
这要从CApplication说起。
<span>abstract</span> <span>class</span> CApplication <span>extends</span><span> CModule { </span><span>public</span> <span>function</span> __construct(<span>$config</span> = <span>null</span><span>) { </span><span>if</span> (<span>is_string</span> ( <span>$config</span><span> )) </span><span>$config</span> = <span>require</span> (<span>$config</span><span>); Yii</span>::setApplication ( <span>$this</span> );<span>//</span><span>保存整个app实例</span> <span>if</span> (<span>isset</span> ( <span>$config</span> ['basePath'<span>] )) { </span><span>$this</span>->setBasePath ( <span>$config</span> ['basePath'<span>] ); </span><span>unset</span> ( <span>$config</span> ['basePath'<span>] ); } </span><span>else</span> <span>$this</span>->setBasePath ( 'protected'<span> ); </span><span>//</span><span>设置别名,后面就可以用application表示basePath了</span> Yii::setPathOfAlias ( 'application', <span>$this</span>-><span>getBasePath () ); </span><span>//</span><span>钩子,模块 预 初始化时执行,子类实现。不过这时,配置还没有写入框架</span> <span>$this</span>-><span>preinit (); </span><span>$this</span>-><span>registerCoreComponents (); </span><span>//</span><span>父类实现</span> <span>$this</span>->configure ( <span>$config</span><span> ); </span><span>//</span><span>加载静态应用组件</span> <span>$this</span>-><span>preloadComponents (); </span><span>//</span><span>这才开始初始化模块</span> <span>$this</span>-><span>init (); }</span>
注意到里面的$this->configure ( $config );,$config是传入的配置文件,是一个数组,非核心文件的定义就是在这里面,比如引入工具类文件夹
<?<span>php </span><span>return</span> <span>array</span><span> ( </span>'basePath' => <span>dirname</span> ( <span>__FILE__</span> ) . DIRECTORY_SEPARATOR . '..', 'import' => <span>array</span><span> ( </span>'application.utils.*'<span> ) ); </span>?>
然后在父类CModule
<span>public</span> <span>function</span> configure(<span>$config</span><span>) { </span><span>if</span> (<span>is_array</span> ( <span>$config</span><span> )) { </span><span>foreach</span> ( <span>$config</span> <span>as</span> <span>$key</span> => <span>$value</span><span> ) </span><span>$this</span>-><span>$key</span> = <span>$value</span><span>; } }</span>
这里yii很"狡猾",它在CModule的父类CComponent中重写了__set()
<span>public</span> <span>function</span> __set(<span>$name</span>,<span>$value</span><span>) { </span><span>$setter</span>='set'.<span>$name</span><span>; </span><span>if</span>(<span>method_exists</span>(<span>$this</span>,<span>$setter</span><span>)) </span><span>return</span> <span>$this</span>-><span>$setter</span>(<span>$value</span><span>); </span><span>else</span>....<span> }</span>
可以看到,如果CModule中如果有设置yii指定参数(比如import)的方法,就会调用它,而我之前裁剪的时候,把CModule中的setImport()删掉了。
另外可以看到basePath, params, modules, import, components 是yii保留的参数名。
<span>public</span> <span>function</span> setImport(<span>$aliases</span><span>) { </span><span>foreach</span>(<span>$aliases</span> <span>as</span> <span>$alias</span><span>) Yii</span>::import(<span>$alias</span><span>); }</span>
然后是YiiBase里面的import()
<span>public</span> <span>static</span> <span>function</span> import(<span>$alias</span>, <span>$forceInclude</span> = <span>false</span><span>) { </span><span>if</span> (<span>isset</span> ( self::<span>$_imports</span> [<span>$alias</span>] )) <span>//</span><span>是否已经存在路径</span> <span>return</span> self::<span>$_imports</span> [<span>$alias</span><span>]; </span><span>if</span> (<span>class_exists</span> ( <span>$alias</span>, <span>false</span> ) || <span>interface_exists</span> ( <span>$alias</span>, <span>false</span> ))<span>//</span><span>类是否已经定义,针对如urlManager这样的已定义于$_coreClasses[]的类</span> <span>return</span> self::<span>$_imports</span> [<span>$alias</span>] = <span>$alias</span><span>; </span><span>if</span> ((<span>$pos</span> = <span>strrpos</span> ( <span>$alias</span>, '.' )) === <span>false</span>) <span>//</span><span>直接是文件名</span> <span> { </span><span>//</span><span> try to autoload the class with an autoloader if $forceInclude is true</span> <span>if</span> (<span>$forceInclude</span> && (Yii::autoload ( <span>$alias</span>, <span>true</span> ) || <span>class_exists</span> ( <span>$alias</span>, <span>true</span><span> ))) self</span>::<span>$_imports</span> [<span>$alias</span>] = <span>$alias</span><span>; </span><span>return</span> <span>$alias</span><span>; } </span><span>$className</span> = ( <span>string</span> ) <span>substr</span> ( <span>$alias</span>, <span>$pos</span> + 1<span> ); </span><span>$isClass</span> = <span>$className</span> !== '*'<span>; </span><span>//</span><span>是否为路径+类名</span> <span>if</span> (<span>$isClass</span> && (<span>class_exists</span> ( <span>$className</span>, <span>false</span> ) || <span>interface_exists</span> ( <span>$className</span>, <span>false</span><span> ))) </span><span>return</span> self::<span>$_imports</span> [<span>$alias</span>] = <span>$className</span><span>; </span><span>//</span><span>获取真实路径</span> <span>if</span> ((<span>$path</span> = self::getPathOfAlias ( <span>$alias</span> )) !== <span>false</span><span>) { </span><span>//</span><span>是否以*结尾,如application.utils.*</span> <span>if</span> (<span>$isClass</span><span>) { </span><span>if</span> (<span>$forceInclude</span><span>) { </span><span>if</span> (<span>is_file</span> ( <span>$path</span> . '.php'<span> )) </span><span>require</span> (<span>$path</span> . '.php'<span>); </span><span>else</span> <span>throw</span> <span>new</span> CException ( Yii::t ( 'yii', 'Alias "{alias}" is invalid. Make sure it points to an existing PHP file and the file is readable.', <span>array</span><span> ( </span>'{alias}' => <span>$alias</span><span> ) ) ); self</span>::<span>$_imports</span> [<span>$alias</span>] = <span>$className</span><span>; } </span><span>else</span><span> self</span>::<span>$classMap</span> [<span>$className</span>] = <span>$path</span> . '.php'<span>; </span><span>return</span> <span>$className</span><span>; } </span><span>else</span> <span>//</span><span> a directory</span> <span> { </span><span>if</span> (self::<span>$_includePaths</span> === <span>null</span><span>) { self</span>::<span>$_includePaths</span> = <span>array_unique</span> ( <span>explode</span> ( PATH_SEPARATOR, <span>get_include_path</span><span> () ) ); </span><span>if</span> ((<span>$pos</span> = <span>array_search</span> ( '.', self::<span>$_includePaths</span>, <span>true</span> )) !== <span>false</span><span>) </span><span>unset</span> ( self::<span>$_includePaths</span> [<span>$pos</span><span>] ); } </span><span>array_unshift</span> ( self::<span>$_includePaths</span>, <span>$path</span><span> ); </span><span>if</span> (self::<span>$enableIncludePath</span> && <span>set_include_path</span> ( '.' . PATH_SEPARATOR . <span>implode</span> ( PATH_SEPARATOR, self::<span>$_includePaths</span> ) ) === <span>false</span><span>) self</span>::<span>$enableIncludePath</span> = <span>false</span><span>; </span><span>return</span> self::<span>$_imports</span> [<span>$alias</span>] = <span>$path</span><span>; } } }</span>
一系列的判断,最后走到最后的else,将path写入到$_imports,这时仍然没有include.
include在autoload()
<span>public</span> <span>static</span> <span>function</span> autoload(<span>$className</span><span>) { </span><span>//</span><span> use include so that the error PHP file may appear</span> <span>if</span>(<span>isset</span>(self::<span>$classMap</span>[<span>$className</span><span>])) </span><span>include</span>(self::<span>$classMap</span>[<span>$className</span><span>]); </span><span>elseif</span>(<span>isset</span>(self::<span>$_coreClasses</span>[<span>$className</span><span>])) </span><span>include</span>(self::<span>$_coreClasses</span>[<span>$className</span><span>]); </span><span>else</span><span> { </span><span>//</span><span> include class file relying on include_path</span> <span>if</span>(<span>strpos</span>(<span>$className</span>,'\\')===<span>false</span>) <span>//</span><span> class without namespace</span> <span> { </span><span>if</span>(self::<span>$enableIncludePath</span>===<span>false</span><span>) { </span><span>foreach</span>(self::<span>$_includePaths</span> <span>as</span> <span>$path</span><span>) { </span><span>$classFile</span>=<span>$path</span>.DIRECTORY_SEPARATOR.<span>$className</span>.'.php'<span>; </span><span>if</span>(<span>is_file</span>(<span>$classFile</span><span>)) { </span><span>include</span>(<span>$classFile</span><span>); </span><span>break</span><span>; } } } </span><span>else</span> <span>include</span>(<span>$className</span>.'.php'<span>); } </span><span>return</span> <span>class_exists</span>(<span>$className</span>,<span>false</span>) || <span>interface_exists</span>(<span>$className</span>,<span>false</span><span>); } </span><span>return</span> <span>true</span><span>; }</span>
如果需要include的是非核心文件,那这里的$className只是一个alias,即文件名的前缀。
裁剪的yii http://files.cnblogs.com/TheViper/framework.zip
如果您觉得本文的内容对您有所帮助,您可以打赏我:

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











소셜 네트워킹과 전자상거래를 통합한 플랫폼인 Xiaohongshu는 점점 더 많은 사용자를 끌어들이고 있습니다. 일부 사용자는 Xiaohongshu와 더 나은 상호 작용 경험을 위해 여러 계정을 등록하기를 원합니다. 그렇다면 Xiaohongshu에 여러 계정을 등록하는 방법은 무엇입니까? 1. Xiaohongshu에 여러 계정을 등록하는 방법은 무엇입니까? 1. 다른 휴대폰 번호를 사용하여 등록합니다. 현재 Xiaohongshu는 주로 휴대폰 번호를 사용하여 계정을 등록합니다. 사용자들은 때때로 여러 개의 휴대폰 번호 카드를 구입하여 여러 개의 Xiaohongshu 계정을 등록하는 데 사용하려고 합니다. 그러나 이 방법에는 여러 장의 휴대폰 번호 카드를 구입하는 것이 번거롭고 비용이 많이 들기 때문에 몇 가지 제한 사항이 있습니다. 2. 이메일을 사용하여 등록하세요. 휴대폰 번호 외에도 이메일을 사용하여 Xiaohongshu 계정을 등록할 수 있습니다. 사용자는 여러 개의 이메일 주소를 준비한 후 해당 이메일 주소를 사용하여 계정을 등록할 수 있습니다. 하지만

생활, 엔터테인먼트, 쇼핑, 공유를 통합한 소셜 플랫폼인 Xiaohongshu는 많은 젊은이들의 일상생활에서 없어서는 안 될 부분이 되었습니다. 그렇다면 Xiaohongshu 계정을 등록하는 방법은 무엇입니까? 1. Xiaohongshu 계정을 등록하는 방법은 무엇입니까? 1. Xiaohongshu 공식 웹사이트를 열거나 Xiaohongshu 앱을 다운로드하세요. 아래의 "등록" 버튼을 클릭하면 다양한 등록 방법을 선택할 수 있습니다. 현재 Xiaohongshu는 휴대폰 번호, 이메일 주소 및 제3자 계정(예: WeChat, QQ, Weibo 등) 등록을 지원합니다. 3. 관련 정보를 입력하세요. 선택한 등록 방법에 따라 해당 휴대폰 번호, 이메일 주소 또는 제3자 계정 정보를 입력하세요. 4. 비밀번호를 설정하세요. 계정을 안전하게 보호하려면 강력한 비밀번호를 설정하세요. 5. 인증을 완료합니다. 안내에 따라 휴대폰 인증 또는 이메일 인증을 완료하세요. 6. 개인을 온전케 하라

세계에서 가장 인기 있는 라이프스타일 공유 플랫폼 중 하나인 Xiaohongshu는 수많은 사용자를 끌어 모았습니다. 그렇다면 Xiaohongshu 계정을 등록하는 방법은 무엇입니까? 이번 글에서는 Xiaohongshu 계정 등록 과정을 자세히 소개하고, Xiaohongshu 계정 이상 현상을 복구하는 방법에 대한 질문에 답변해 드리겠습니다. 1. Xiaohongshu 계정을 등록하는 방법은 무엇입니까? 1. Xiaohongshu 앱 다운로드: 모바일 앱 스토어에서 Xiaohongshu 앱을 검색하여 다운로드하고 설치가 완료된 후 엽니다. 2. 계정 등록: Xiaohongshu 앱을 연 후 홈페이지 오른쪽 하단에 있는 '나' 버튼을 클릭한 후 '등록'을 선택하세요. 3. 등록 정보 입력: 프롬프트에 따라 휴대폰 번호, 비밀번호, 인증 코드 및 기타 등록 정보를 입력합니다. 4. 개인정보 입력: 등록이 완료되면 안내에 따라 이름, 성별, 생일 등 개인정보를 입력하세요. 5. 설정

우리가 노래를 듣기 위해 이 플랫폼을 사용할 때, 대부분은 듣고 싶은 노래가 있어야 합니다. 물론 저작권이 없기 때문에 듣지 못할 수도 있습니다. 물론 일부 노래를 직접 사용할 수도 있습니다. 현지에서 수입한 것입니다. 올라가서 들어보세요. 일부 노래를 다운로드하고 mp3 형식으로 직접 변환하여 가져오기 및 기타 상황을 위해 휴대폰에서 스캔할 수 있습니다. 하지만 대부분의 사용자는 로컬 노래 콘텐츠 가져오기에 대해 잘 모르므로 이러한 문제를 잘 해결하기 위해 오늘 편집자는 묻지 않고도 더 나은 선택을 할 수 있도록 설명합니다. 당신은 관심이 있습니다,

qooapp은 많은 게임을 다운로드할 수 있는 소프트웨어인데 계정을 등록하는 방법은 무엇입니까? 아직 패스가 없는 경우 "등록" 버튼을 클릭한 후 등록 방법을 선택해야 합니다. 이 계정 등록 방법 소개는 사용법을 설명하기에 충분합니다. 다음은 자세한 소개이므로 살펴보십시오. qooapp 계정을 등록하는 방법 답변: 등록을 클릭한 후 등록 방법을 선택하세요. 구체적인 방법: 1. 로그인 인터페이스에 들어간 후 아직 패스가 없습니까? 2. 그런 다음 필요한 로그인 방법을 선택하십시오. 3. 그 후 바로 사용하시면 됩니다. 공식 웹사이트 등록: 1. 웹사이트 https://apps.ppaooq.com/을 열고 오른쪽 상단을 클릭하여 등록합니다. 2. 등록 선택

WeChat 비디오 계정이 출시되면서 점점 더 많은 사람들이 새로운 트래픽 기회를 보게 되었습니다. 따라서 비디오 계정 매트릭스 계정을 등록하는 것이 많은 제작자와 판매자의 초점이 되었습니다. 그렇다면 비디오 번호 매트릭스 계정을 등록하는 방법은 무엇입니까? 나만의 비디오 계정을 만드는 방법은 무엇입니까? 이 기사에서는 이 두 가지 질문에 대해 자세히 답변할 것입니다. 1. 비디오 번호 매트릭스 계정을 등록하는 방법은 무엇입니까? 1. 위챗 계정: 먼저 위챗 계정이 필요합니다. 그렇지 않은 경우 먼저 등록하십시오. 2. 비디오 계정 개설: WeChat 앱에서 "검색" 페이지를 찾아 "비디오 계정"을 클릭하여 비디오 계정 페이지로 들어갑니다. 3. 크리에이터 센터: 영상 계정 페이지 하단의 '크리에이터 센터' 버튼을 클릭해 크리에이터 센터로 들어갑니다. 4. 비디오 계정 등록: 크리에이터 센터 페이지에서 "비디오 계정 등록" 옵션을 찾으세요.

Bilibili(빌리빌리)는 중국 젊은이들 사이에서 큰 인기를 얻고 있는 동영상 공유 웹사이트로 많은 사용자를 유치하고 있습니다. 일부 사용자는 별도로 관리하고 사용할 수 있도록 두 개의 Bilibili 계정을 갖고 싶어합니다. 그렇다면 하나의 휴대폰 번호로 두 개의 B 사이트 번호를 등록하는 방법은 무엇입니까? 이 기사에서는 이 문제와 휴대폰 바인딩을 해제하는 방법에 중점을 둘 것입니다. 1. 하나의 휴대폰 번호로 두 개의 B 사이트 번호를 등록하는 방법은 무엇입니까? 1. 새 계정 등록: 먼저 휴대폰에서 Bilibili 앱을 열거나 공식 웹사이트에 로그인한 후 "등록" 버튼을 클릭하고 휴대폰 번호, 이메일 또는 제3자를 사용하여 등록 방법을 선택할 수 있습니다. 당사자 계정(예: WeChat, QQ 등)을 등록합니다. 2. 계정 등록 시 시스템 안내에 따라 휴대전화 번호, 인증번호, 비밀번호 설정 등 필요한 정보를 입력하세요. 반드시 다른 계정을 사용하세요

WeChat은 풍부한 기능과 많은 사용자를 갖춘 인기 있는 소셜 소프트웨어입니다. 귀하가 WeChat에 등록한 기간을 확인하려는 경우, WeChat 자체에서 등록 시간 확인 기능을 직접 제공하지는 않지만 몇 가지 간접적인 방법을 통해 추측할 수 있습니다. 그러나 다양한 요인이 결과의 정확성에 영향을 미칠 수 있으므로 이러한 방법은 절대적으로 정확하지는 않습니다. 등록 시간에 대한 정확한 요구 사항이 있는 경우 WeChat 고객 서비스에 문의하여 상담하는 것이 좋습니다. WeChat 등록 후 얼마나 지났는지 어떻게 확인하나요? WeChat에 등록된 기간을 확인하는 첫 번째 방법은 QQ 메일함을 확인하는 것입니다. QQ를 사용하여 WeChat에 로그인하는 경우 등록이 성공적으로 완료되면 QQ 사서함에 WeChat에서 보낸 환영 이메일이 전송됩니다. QQ 메일함에서 "WeChat"을 검색하여 해당 이메일이 있는지 확인한 후 등록 시간을 확인할 수 있습니다. 두 번째 방법은 살펴보는 것입니다.
