chilimatic / framework
chilimatic 框架,激发好奇心
Requires
- php: >=5.4
Requires (Dev)
- phpdocumentor/phpdocumentor: 2.*
- phpunit/phpunit: 4.5.*
This package is auto-updated.
Last update: 2024-09-09 13:14:13 UTC
README
chilimatic-framework
这只是为了反馈 :) 如果觉得有用,请fork它,使用它,如果有好的想法,请告诉我
#前言
在有些地方,我故意违反了最佳实践,这是基于PHP解释器的结构。这些决定自然可以争论。在开始讨厌之前,这里有一个例子。
节点获取器和设置器。它们仍然存在,但所有属性都是公共的,这与在phpng之前的行为有关 http://jpauli.github.io/2015/01/22/on-php-function-calls.html。我需要用新引擎对其进行基准测试,因为它们已经改变了函数调用的行为,所以它们具有更少的开销和更好的性能。
https://drive.google.com/file/d/0B3UKOMH_4lgBUTdjUGxIZ3l1Ukk/view
我非常乐观,我可以用它们再次。但如果你使用数百个节点,结构会比使用公共访问方法调用慢。因此,图结构应该是一个私有属性,但图内部的一切都是公共的。
同样的情况也适用于数组。在PHP7之前,我不会推荐使用超过1000个节点 -> 看数组的内存分配 https://nikic.github.io/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.html
但如https://drive.google.com/file/d/0B3UKOMH_4lgBUTdjUGxIZ3l1Ukk/view所述,你可以看到他们已经改变了PHP数组的结构 [从PDF中复制]
- 散列表大小从72字节减少到56字节
- 桶大小从72字节减少到32字节
- 所有桶的内存一次性分配
- Bucket.key现在是指向zend_string的指针,它不需要被复制(只需增加引用计数器即可)
- 数组元素的值嵌入到桶中
- 改进了数据局部性 => 减少了CPU缓存未命中
这意味着
$a = array();
for ($i = 0; $i < 1000000; $i++) $a[$i] = array("hello");
echo memory_get_usage(true);
内存使用量 428 MB [旧] 33 MB [新] 时间 0.49 秒[旧] 0.06 秒 [新]
这很重要,因为内存总是有问题,尤其是因为unset() 使用垃圾回收器。如果你比较大量数据,你不能使用unset,因为GC不会立即收集它,而是“当他觉得最好”时,这意味着你会耗尽内存,所以你需要将值置为null以立即释放一些内存 .....
配置
这是一个基于域的配置系统
- *.cfg
- *.example.com.cfg
- subdomain.example.com.cfg
这里的 *.cfg 是根配置,它将是第一个被 *.example.com 覆盖的设置,它将被 subdomain.example.com.cfg 覆盖
例如
use \chilimatic\lib\config\Config;
Config::getInstance(
[
'type' => 'File',
<path/to/folder/withconfigfiles>
]
);
*.cfg的内容
# page settings
default_timezone = 'Europe/Vienna'
default_page_encoding = 'utf-8'
#cache settings
cache_type = 'memcached'
cache_settings = { "server_list" : [{"host" : "127.0.0.1", "port" : "11211", "weight" : 1 }] }
#Session data
session_type = "Cache"
session_cache = 'Memcached'
*.example.com的内容
session_type = "Mysql"
所以如果你在example.com域名上使用
Config::get('session_type'); // returns Mysql
Config::get('cache_settings') // return \stdClass containing the json
这是一个如何使用配置对象的简单示例
对于单例来说,这是一个反模式! :) 在这种情况下,单例只是一个包装任何配置的容器
use \chilimatic\lib\config\File as Config;
$config = new Config([\chilimatic\lib\config\File::CONFIG_PATH_INDEX => <path/to/folder/withconfigfiles>]);
或者工厂
use \chilimatic\lib\config\ConfigFactory;
$config = ConfigFactory::make('File',[\chilimatic\lib\config\File::CONFIG_PATH_INDEX => <path/to/folder/withconfigfiles>] );
数组是一个接口问题,因为ini可以接受多个参数,如果它们在PHP7中确认了这个,我会只为PHP7实现它 https://wiki.php.net/rfc/named_params
DI
让我们考虑一下服务收集,默认服务收集可以在
lib/general/config/default-service-collection.php
这只是一个示例。我采用了闭包方法,这样更容易添加一个服务作为示例。
$dispatcher = \chilimatic\lib\di\ClosureFactory::getInstance(
realpath('<path to your closure collection>');
);
// set a db object
$dispatcher->set('db', function() use ($dispatcher) {
$config = $dispatcher->get('config');
$mysqlStorage = new \chilimatic\lib\database\mysql\MysqlConnectionStorage();
$mysqlStorage->addConnection(
$config->get('mysql_db_host'),
$config->get('mysql_db_user'),
$config->get('mysql_db_password'),
$config->get('mysql_db_name'),
null
);
return $mysqlStorage;
});
$dispatcher->set('entity-manager', function() use ($dispatcher) {
$mysqlStorage = $dispatcher->get('db');
$master = $mysqlStorage->getConnection(0);
$queryBuilder = $dispatcher->get('query-builder', ['db' => new \chilimatic\lib\database\mysql\Mysql($master)]);
$em = new \chilimatic\lib\database\orm\EntityManager(
new \chilimatic\lib\database\mysql\Mysql($master),
$queryBuilder
);
return $em;
});
// get a new instance
$dispatcher->get('db', []);
// get it as "singelton"
$dispatcher->get('em', [], true);
但是让我们从一个基本的应用程序示例开始,这样您可以尝试一下。您创建“基本”结构
<path>
- app
- config
- *.cfg
- *.example.com.cfg
- www.example.com.cfg
- module
- main [default]
- controller
- Index.php
- view
- index.phtml
- public [Docroot]
- index.php
- vendor/chilimatic/framework/lib [framework]
public/index.php的内容
<?php
require_once '../vendor/autoload.php';
define('APPLICATION_PATH', realpath('../'));
try {
use chilimatic\lib\config\Config;
date_default_timezone_set('Europe/Vienna');
define('INCLUDE_ROOT', '/var/www/chilimatic.com' );
set_exception_handler(function($e)
{
echo $e->getMessage();
echo $e->getTraceAsString();
});
$dispatcher = \chilimatic\lib\di\ClosureFactory::getInstance(
realpath('../app/config/serviceCollection.php')
);
/**
* Create the config
*/
$config = $dispatcher->get('config', [
'type' => 'File',
\chilimatic\lib\config\File::CONFIG_PATH_INDEX => INCLUDE_ROOT . '/app/config/'
]);
/**
* Set default timezone based on the config
*/
date_default_timezone_set((string) $config->get('default_timezone'));
if (!$config->get((string) 'document_root')) {
$config->set((string) 'document_root', (string) INCLUDE_ROOT);
}
$config->set('app_root', (string) $config->get('document_root') . (string) "/app");
$config->set('lib_root', (string) $config->get('document_root') . (string) $config->get('lib_dir' ));
$application = new \chilimatic\lib\application\HTTPMVC($dispatcher, $dispatcher->get('config'));
// this is step so people can inject
$application->init();
// returns the rendered result
echo $application->getHandler()->getContent();
}
catch (Exception $e)
{
// show error trace
if (isset($dispatcher) && $dispatcher->get('error-handler', null, true)->getClient()->showError()) {
$dispatcher->get('error-handler', null, true)->getClient()->log($e->getMessage(), $e->getTraceAsString())->send();
} else {
echo 'nothing to concern you with :)';
}
app/module/main/controller/Index.php的内容
namespace chilimatic\app\module\main\controller;
/**
* Class Index
* @package \chilimatic\app\default\controller
*/
class Index
{
/**
* Class Index
* @view \chilimatic\lib\view\PHtml()
*/
public function indexAction(){
$this->view->pageTitle = 'myPage';
}
}
app/module/main/view/index.phtml的内容
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title><?php echo $this->pageTitle; ?></title>
</head>
<body></body>
</html>
数据结构
普通的“节点”
$node = new \chilimatic\lib\datastructure\graph\Node(null, '.', '');
$node->addChild(new \chilimatic\lib\datastructure\graph\Node($node, 'test', 23));
$node->getChildren(); // return [\chilimatic\lib\datastructure\graph\Node($node, 'test', 23)]
$node->getLastByKey("test"); // return \chilimatic\lib\datastructure\graph\Node($node, 'test', 23)
$node->getLastByKey("test")->getData(); // return 23
二叉树
$bt = \chilimatic\lib\datastructure\graph\tree\binary\BinaryTree();
$bt->insert(\chilimatic\lib\datastructure\graph\tree\binary\BinaryNode('key', [1,2,3]));
$bt->insert(\chilimatic\lib\datastructure\graph\tree\binary\BinaryNode('key1', [1,2,3]));
$bt->findByKey('key1'); // returns \chilimatic\lib\datastructure\graph\tree\binary\BinaryNode('key1', [1,2,3])
会话
您可以轻松实现自己的会话存储系统
// uses memcached as session storage
$session = new chilimatic\lib\session\handler\Session(
chilimatic\lib\session\engine\Factory::make('Cache', ['type' => 'memcached'])
);
$session->set('value', 'data');
$session->get('value'); // returns data
路由
可能的类型包括
- stdclass
- 数组(数字索引)
- 数组(关联索引)
- lambda函数
- 函数调用
- 静态内容
路由存储在二叉树中,因此我希望它的性能很好,您始终可以回退到常见的路由
\chilimatic\route\Router::register('/test/(:num)', array('job', 'load'), '/');
\chilimatic\route\Router::register('/user/add/(:num)', array('object' => 'user', 'method' => 'add', 'namespace' => '\\user\\', 'param' => array(true, false)));
\chilimatic\route\Route::register('/test/(:char)', array('object' => 'user', 'method' => 'add', 'namespace' => '\\user\\', 'param' => array(true, false)));
\chilimatic\route\Route::register('/mytest/(:array)[|]', function($num) { foreach($num as $val) { echo $val . ': this is a test'; }});
缓存
$cache = \chilimatic\lib\cache\engine\CacheFactory::make('memcached', []);
// this will get you a memcached I added a listing for memcached so you can actually see
$cache->set('myData', [], $ttl = 10)
$cache->listCache(); // returns ['myData', {'data'}]
$cache->delete('myData'); // returns true
$cache->listCache(); // returns []
##ORM / 数据库
// you can have multiple connections in the storage -> if you just want to use pdo / mysqli
$mysqlStorage = new \chilimatic\lib\database\mysql\MysqlConnectionStorage();
$mysqlStorage->addConnection('localhost','username', 'password', 'database';
$master = $mysqlStorage->getConnection(0);
// the entity manager
$em = new \chilimatic\lib\database\orm\EntityManager(new \chilimatic\lib\database\mysql\Mysql($master));
// the entityManager needs the corret QueryBuilder -> atm there is only MySQL supportet
$queryBuilder = new \chilimatic\lib\database\orm\querybuilder\MysqlQueryBuilder();
$queryBuilder->setCache(\chilimatic\lib\di\ClosureFactory::getInstance()->get('cache', ['type' => 'shmop']));
$em->setQueryBuilder($queryBuilder);
/**
* Class Model
*
* @package \app\model
*/
class Model1 extends AbstractModel {
/**
* @var int
*/
protected $id;
/**
* @var int
*/
protected $model2_id;
/**
* maps it to the model2 id and adds the model here
* @ORM model2_id = \Model2;
*/
protected $model2;
/**
* @param int $id
*/
public function setModel1($id) {
$this->model1 = (int) $id;
}
/**
* @param int $id
*/
public function setModel2($id) {
$this->model2 = (int) $id;
}
/**
* @return array
*/
public function jsonSerialize() {
return [
'id' => $id,
'model2_id' => $model2_id
];
}
}
/**
* Class Model2
* @ORM table=database.anyTable;
*/
class Model2 extends AbstractModel {
/**
* @var int
*/
protected $id;
}
// returns the model
$model1 = $em->findOneBy(new Model1(), [
'id' => 1
]);
$model1->setModel2(3);
$em->persist($model1); // updates the model
// create a new entry
$newModel = new Model1();
$newModel->setModel1(2);
$newModel->setModel2(3);
// creates a new table entry
$em->persist($newModel);
整个框架主要是学术性的,但如果您发现一个不错的应用程序想要使用它,或者您只是想看看一些概念或给我一些有用的反馈,我将非常高兴。
节点过滤器
这是我从Doctrine采取的方法。这是一个基本的过滤器系统。
$filterFactory = new \chilimatic\lib\datastructure\graph\filter\Factory();
// the validator checks if the name is conform to the convetions this-will-be
$filterFactory->setValidator(new chilimatic\lib\validator\DynamicCallNamePreTransformed());
// the transformer will change the this-will-be string to ThisWillBe
$filterFactory->setTransformer(new chilimatic\lib\transformer\string\DynamicObjectCallName());
$filterLastNode = $filterFactory->make('lastNode');
$filterFirstNode = $filterFactory->make('firstNode');
// so lets create a bunch of nodes
$mainNode = new \chilimatic\lib\datastructure\graph\Node($node, 'test', null);
for ($i = 0; $i < 10; $i++) {
$mainNode->addChild(new \chilimatic\lib\datastructure\graph\Node($node, 'test', $i))
}
$mainNode->getByKey('test', $filterLastNode); // this should return the node with the value 10
$mainNode->getByKey('test', $filterFirstNode); // this should return the node with the value 0